//>> AndExpr ::= ( AndExpr 'and' )? EqualityExpr private AstNode ParseAndExpr(AstNode qyInput) { AstNode opnd = ParseEqualityExpr(qyInput); do { if (! TestOp("and")) { return opnd; } NextLex(); opnd = new Operator(Operator.Op.AND, opnd, ParseEqualityExpr(qyInput)); }while (true); }
//>> OrExpr ::= ( OrExpr 'or' )? AndExpr private AstNode ParseOrExpr(AstNode qyInput) { AstNode opnd = ParseAndExpr(qyInput); do { if (! TestOp("or")) { return opnd; } NextLex(); opnd = new Operator(Operator.Op.OR, opnd, ParseAndExpr(qyInput)); }while (true); }
//>> EqualityOp ::= '=' | '!=' //>> EqualityExpr ::= ( EqualityExpr EqualityOp )? RelationalExpr private AstNode ParseEqualityExpr(AstNode qyInput) { AstNode opnd = ParseRelationalExpr(qyInput); do { Operator.Op op = ( this.scanner.Kind == XPathScanner.LexKind.Eq ? Operator.Op.EQ : this.scanner.Kind == XPathScanner.LexKind.Ne ? Operator.Op.NE : /*default :*/ Operator.Op.INVALID ); if (op == Operator.Op.INVALID) { return opnd; } NextLex(); opnd = new Operator(op, opnd, ParseRelationalExpr(qyInput)); }while (true); }
private IQuery ProcessNode(AstNode root, IQuery qyInput,int parent, Axis.AxisType parentaxis, ref bool cache, ref bool position) { IQuery result = null; if (root == null) return null; switch (root.TypeOfAst) { case AstNode.QueryType.Axis: filterCount = 0; firstInput = null; Axis axis = (Axis)root; if (axis.TypeOfAxis == Axis.AxisType.Descendant || axis.TypeOfAxis == Axis.AxisType.DescendantOrSelf) if (_smart > 0) { result = ProcessAxis( axis, ProcessNode(axis.Input, qyInput,Smart_D, axis.TypeOfAxis, ref cache, ref position), parent, parentaxis); break; } _smart++; result = ProcessAxis( axis, ProcessNode(axis.Input, qyInput,Regular_D, axis.TypeOfAxis, ref cache, ref position), parent, parentaxis); _smart--; break; case AstNode.QueryType.Operator: _smart = 2; result = ProcessOperator((Operator)root, null, ref cache, ref position); break; case AstNode.QueryType.Filter: _smart = 2; result = ProcessFilter((Filter)root, ref cache, ref position); break; case AstNode.QueryType.ConstantOperand: result = ProcessOperand((Operand)root); break; case AstNode.QueryType.Variable: result = ProcessVariable((Variable)root); break; case AstNode.QueryType.Function: result = ProcessFunction( (System.Xml.XPath.Function)root, qyInput, ref cache, ref position); break; case AstNode.QueryType.Group: _smart = 2; result = new GroupQuery(ProcessNode( ((System.Xml.XPath.Group)root).GroupNode, qyInput,Regular_D, Axis.AxisType.None, ref cache, ref position)); break; case AstNode.QueryType.Root: result = new AbsoluteQuery(); break; default: Debug.Assert(false, "Unknown QueryType encountered!!"); break; } return result; }
internal static string ComposeXPath(AstNode node) { StringBuilder expr = new StringBuilder(); ComposeExpression(node, expr); return expr.ToString(); }
//>> PathOp ::= '/' | '//' //>> RelativePathPattern ::= ( RelativePathPattern PathOp )? StepPattern private AstNode ParseRelativePathPattern(AstNode qyInput) { AstNode opnd = ParseStepPattern(qyInput); if (XPathScanner.LexKind.SlashSlash == this.scanner.Kind) { NextLex(); opnd = ParseRelativePathPattern(new Axis(Axis.AxisType.DescendantOrSelf, opnd)); } else if (XPathScanner.LexKind.Slash == this.scanner.Kind) { NextLex(); opnd = ParseRelativePathPattern(opnd); } return opnd; }
// --------------- Pattern Parsing ---------------------- //>> Pattern ::= ( Pattern '|' )? LocationPathPattern private AstNode ParsePattern(AstNode qyInput) { AstNode opnd = ParseLocationPathPattern(qyInput); do { if (this.scanner.Kind != XPathScanner.LexKind.Union) { return opnd; } NextLex(); opnd = new Operator(Operator.Op.UNION, opnd, ParseLocationPathPattern(qyInput)); }while (true); }
private AstNode ParseMethod(AstNode qyInput) { ArrayList argList = new ArrayList(); string name = this.scanner.Name; string prefix = this.scanner.Prefix; PassToken(XPathScanner.LexKind.Name); PassToken(XPathScanner.LexKind.LParens); if (this.scanner.Kind != XPathScanner.LexKind.RParens) { do { argList.Add(ParseExpresion(qyInput)); if (this.scanner.Kind == XPathScanner.LexKind.RParens) { break; } PassToken(XPathScanner.LexKind.Comma); }while (true); } PassToken(XPathScanner.LexKind.RParens); if (prefix == string.Empty) { ParamInfo pi = (ParamInfo) functionTable[name]; if (pi != null) { int argCount = argList.Count; if (argCount < pi.Minargs) { throw new XPathException(Res.Xp_InvalidNumArgs, name, this.scanner.SourceText); } if (pi.FType == Function.FunctionType.FuncConcat) { for (int i = 0; i < argCount; i ++) { AstNode arg = (AstNode)argList[i]; if (arg.ReturnType != XPathResultType.String) { arg = new Function(Function.FunctionType.FuncString, arg); } argList[i] = arg; } } else { if (pi.Maxargs < argCount) { throw new XPathException(Res.Xp_InvalidNumArgs, name, this.scanner.SourceText); } if (pi.ArgTypes.Length < argCount) { argCount = pi.ArgTypes.Length; // argument we have the type specified (can be < pi.Minargs) } for (int i = 0; i < argCount; i ++) { AstNode arg = (AstNode)argList[i]; if ( pi.ArgTypes[i] != XPathResultType.Any && pi.ArgTypes[i] != arg.ReturnType ) { switch (pi.ArgTypes[i]) { case XPathResultType.NodeSet : if (!(arg is Variable) && !(arg is Function && arg.ReturnType == XPathResultType.Error) ) { throw new XPathException(Res.Xp_InvalidArgumentType, name, this.scanner.SourceText); } break; case XPathResultType.String : arg = new Function(Function.FunctionType.FuncString, arg); break; case XPathResultType.Number : arg = new Function(Function.FunctionType.FuncNumber, arg); break; case XPathResultType.Boolean : arg = new Function(Function.FunctionType.FuncBoolean, arg); break; } argList[i] = arg; } } } return new Function(pi.FType, argList); } } return new Function(prefix, name, argList); }
//>> MultiplicativeOp ::= '*' | 'div' | 'mod' //>> MultiplicativeExpr ::= ( MultiplicativeExpr MultiplicativeOp )? UnaryExpr private AstNode ParseMultiplicativeExpr(AstNode qyInput) { AstNode opnd = ParseUnaryExpr(qyInput); do { Operator.Op op = ( this.scanner.Kind == XPathScanner.LexKind.Star ? Operator.Op.MUL : TestOp("div") ? Operator.Op.DIV : TestOp("mod") ? Operator.Op.MOD : /*default :*/ Operator.Op.INVALID ); if (op == Operator.Op.INVALID) { return opnd; } NextLex(); opnd = new Operator(op, opnd, ParseUnaryExpr(qyInput)); }while (true); }
//>> AdditiveOp ::= '+' | '-' //>> AdditiveExpr ::= ( AdditiveExpr AdditiveOp )? MultiplicativeExpr private AstNode ParseAdditiveExpr(AstNode qyInput) { AstNode opnd = ParseMultiplicativeExpr(qyInput); do { Operator.Op op = ( this.scanner.Kind == XPathScanner.LexKind.Plus ? Operator.Op.PLUS : this.scanner.Kind == XPathScanner.LexKind.Minus ? Operator.Op.MINUS : /*default :*/ Operator.Op.INVALID ); if (op == Operator.Op.INVALID) { return opnd; } NextLex(); opnd = new Operator(op, opnd, ParseMultiplicativeExpr(qyInput)); }while (true); }
//>> RelationalOp ::= '<' | '>' | '<=' | '>=' //>> RelationalExpr ::= ( RelationalExpr RelationalOp )? AdditiveExpr private AstNode ParseRelationalExpr(AstNode qyInput) { AstNode opnd = ParseAdditiveExpr(qyInput); do { Operator.Op op = ( this.scanner.Kind == XPathScanner.LexKind.Lt ? Operator.Op.LT : this.scanner.Kind == XPathScanner.LexKind.Le ? Operator.Op.LE : this.scanner.Kind == XPathScanner.LexKind.Gt ? Operator.Op.GT : this.scanner.Kind == XPathScanner.LexKind.Ge ? Operator.Op.GE : /*default :*/ Operator.Op.INVALID ); if (op == Operator.Op.INVALID) { return opnd; } NextLex(); opnd = new Operator(op, opnd, ParseAdditiveExpr(qyInput)); }while (true); }
//TRy Changing the algorthim to simplify private static bool CalculatePriorities(Compiler compiler, AstNode node, TemplateAction right) { switch (node.TypeOfAst) { case AstNode.QueryType.Operator: Operator op = (Operator) node; if (op.OperatorType == Operator.Op.UNION) { TemplateAction left = right.Clone(); if (CalculatePriorities(compiler, op.Operand1, left)) { left.FinishClone(compiler, op.Operand1); } compiler.AddTemplate(left); if (CalculatePriorities(compiler, op.Operand2, right)) { right.FinishClone(compiler, op.Operand2); } return false; } break; //case AstNode.QueryType.Group: // return CalculatePriorities(compiler, ((Group)node).GroupNode, right); } return true; }
private void FinishClone(Compiler compiler, AstNode node) { string expression = XPathComposer.ComposeXPath(node); Debug.WriteLine("Split expression: \"" + expression + "\""); this.match = expression; this.matchKey = compiler.AddQuery(this.match); this.priority = node.DefaultPriority; }
private void ProcessNode(int index, AstNode node, Hashtable hashtable, ref SortedList list) { if (node == null) return; switch (node.TypeOfAst) { case AstNode.QueryType.Axis: ProcessNode(index,((Axis)node).Input, hashtable, ref list); break; case AstNode.QueryType.Operator: Operator op = node as Operator; ProcessNode(index, op.Operand1, hashtable, ref list); ProcessNode(index, op.Operand2, hashtable, ref list); break; case AstNode.QueryType.Filter: Filter filter = node as Filter; ProcessNode(index, filter.Input, hashtable, ref list); ProcessNode(index, filter.Condition, hashtable, ref list); break; case AstNode.QueryType.ConstantOperand: break; case AstNode.QueryType.Variable: String name = ((Variable)node).Name; if (hashtable.Contains(name)){ int i = (int)hashtable[name]; if (i == index) throw new XsltException(Res.Xslt_CircularReference, name); if (!list.ContainsKey(i)) list.Add(i, i); } break; case AstNode.QueryType.Function: int count = 0; Function function = node as Function; while (count < function.ArgumentList.Count) { ProcessNode(index, (AstNode)function.ArgumentList[count++], hashtable, ref list); } break; case AstNode.QueryType.Group: ProcessNode(index, ((Group)node).GroupNode, hashtable, ref list); break; case AstNode.QueryType.Root: break; } }
internal IQuery Build(AstNode root, String query) { // before we go off and build the query tree for essentially // brute force walking of the tree, let's see if we recognize // the abstract syntax tree (AST) to be one of the 6 special // patterns that we already know about. reset(); _query = query; bool flag1 = false, flag2 = false; return ProcessNode(root, null,Regular_D, Axis.AxisType.None, ref flag1, ref flag2); } //Build
//>> NodeTest ::= NameTest | 'comment ()' | 'text ()' | 'node ()' | 'processing-instruction (' Literal ? ')' private AstNode ParseNodeTest(AstNode qyInput, Axis.AxisType axisType, XPathNodeType nodeType) { string nodeName, nodePrefix; switch (this.scanner.Kind) { case XPathScanner.LexKind.Name : if (this.scanner.CanBeFunction && IsNodeType(this.scanner)) { nodePrefix = string.Empty; nodeName = string.Empty; nodeType = ( this.scanner.Name == "comment" ? XPathNodeType.Comment : this.scanner.Name == "text" ? XPathNodeType.Text : this.scanner.Name == "node" ? XPathNodeType.All : this.scanner.Name == "processing-instruction" ? XPathNodeType.ProcessingInstruction : /* default: */ XPathNodeType.Root ); Debug.Assert(nodeType != XPathNodeType.Root); NextLex(); PassToken(XPathScanner.LexKind.LParens); if (nodeType == XPathNodeType.ProcessingInstruction) { if (this.scanner.Kind != XPathScanner.LexKind.RParens) { //>> 'processing-instruction (' Literal ')' CheckToken(XPathScanner.LexKind.String); nodeName = this.scanner.StringValue; NextLex(); } } PassToken(XPathScanner.LexKind.RParens); } else { nodePrefix = this.scanner.Prefix; nodeName = this.scanner.Name; NextLex(); if (nodeName == "*") { nodeName = string.Empty; } } break; case XPathScanner.LexKind.Star : nodePrefix = string.Empty; nodeName = string.Empty; NextLex(); break; default : throw new XPathException(Res.Xp_NodeSetExpected, this.scanner.SourceText); } return new Axis(axisType, qyInput, nodePrefix, nodeName, nodeType); }
//>> PrimaryExpr ::= Literal | Number | VariableReference | '(' Expr ')' | FunctionCall private AstNode ParsePrimaryExpr(AstNode qyInput) { Debug.Assert(IsPrimaryExpr(this.scanner)); AstNode opnd = null; switch (this.scanner.Kind) { case XPathScanner.LexKind.String: opnd = new Operand(this.scanner.StringValue); NextLex(); break; case XPathScanner.LexKind.Number: opnd = new Operand(this.scanner.NumberValue); NextLex(); break; case XPathScanner.LexKind.Dollar: NextLex(); CheckToken(XPathScanner.LexKind.Name); opnd = new Variable(this.scanner.Name, this.scanner.Prefix); NextLex(); break; case XPathScanner.LexKind.LParens: NextLex(); opnd = ParseExpresion(qyInput); if (opnd.TypeOfAst != AstNode.QueryType.ConstantOperand) { opnd = new Group(opnd); } PassToken(XPathScanner.LexKind.RParens); break; case XPathScanner.LexKind.Name : if (this.scanner.CanBeFunction && ! IsNodeType(this.scanner)) { opnd = ParseMethod(null); } break; } Debug.Assert(opnd != null, "IsPrimaryExpr() was true. We should recognize this lex."); return opnd; }
//>> UnaryExpr ::= UnionExpr | '-' UnaryExpr private AstNode ParseUnaryExpr(AstNode qyInput) { if (this.scanner.Kind == XPathScanner.LexKind.Minus) { NextLex(); return new Operator(Operator.Op.NEGATE, ParseUnaryExpr(qyInput), null); } else { return ParseUnionExpr(qyInput); } }
// --------------- Expresion Parsing ---------------------- private AstNode ParseExpresion(AstNode qyInput) { return ParseOrExpr(qyInput); }
//>> UnionExpr ::= ( UnionExpr '|' )? PathExpr private AstNode ParseUnionExpr(AstNode qyInput) { AstNode opnd = ParsePathExpr(qyInput); do { if (this.scanner.Kind != XPathScanner.LexKind.Union) { return opnd; } NextLex(); AstNode opnd2 = ParsePathExpr(qyInput); CheckNodeSet(opnd.ReturnType); CheckNodeSet(opnd2.ReturnType); opnd = new Operator(Operator.Op.UNION, opnd, opnd2); }while (true); }
//>> LocationPathPattern ::= '/' | RelativePathPattern | '//' RelativePathPattern | '/' RelativePathPattern //>> | IdKeyPattern (('/' | '//') RelativePathPattern)? private AstNode ParseLocationPathPattern(AstNode qyInput) { AstNode opnd = null; switch (this.scanner.Kind) { case XPathScanner.LexKind.Slash : NextLex(); opnd = new Root(); if (this.scanner.Kind == XPathScanner.LexKind.Eof || this.scanner.Kind == XPathScanner.LexKind.Union) { return opnd; } break; case XPathScanner.LexKind.SlashSlash : NextLex(); opnd = new Axis(Axis.AxisType.DescendantOrSelf, new Root()); break; case XPathScanner.LexKind.Name : if (this.scanner.CanBeFunction) { opnd = ParseIdKeyPattern(qyInput); if (opnd != null) { switch (this.scanner.Kind) { case XPathScanner.LexKind.Slash : NextLex(); break; case XPathScanner.LexKind.SlashSlash : NextLex(); opnd = new Axis(Axis.AxisType.DescendantOrSelf, opnd); break; default : return opnd; } } } break; } return ParseRelativePathPattern(opnd); }
//>> PathOp ::= '/' | '//' //>> PathExpr ::= LocationPath | //>> FilterExpr ( PathOp RelativeLocationPath )? private AstNode ParsePathExpr(AstNode qyInput) { AstNode opnd; if (IsPrimaryExpr(this.scanner)) { // in this moment we shoud distinct LocationPas vs FilterExpr (which starts from is PrimaryExpr) opnd = ParseFilterExpr(qyInput); if (this.scanner.Kind == XPathScanner.LexKind.Slash) { NextLex(); opnd = ParseRelativeLocationPath(opnd); } else if (this.scanner.Kind == XPathScanner.LexKind.SlashSlash) { NextLex(); opnd = ParseRelativeLocationPath(new Axis(Axis.AxisType.DescendantOrSelf, opnd)); } } else { opnd = ParseLocationPath(null); } return opnd; }
//>> IdKeyPattern ::= 'id' '(' Literal ')' | 'key' '(' Literal ',' Literal ')' private AstNode ParseIdKeyPattern(AstNode qyInput) { Debug.Assert(this.scanner.CanBeFunction); ArrayList argList = new ArrayList(); if (this.scanner.Prefix.Length == 0) { if (this.scanner.Name == "id") { ParamInfo pi = (ParamInfo) functionTable["id"]; NextLex();; PassToken(XPathScanner.LexKind.LParens); CheckToken(XPathScanner.LexKind.String); argList.Add(new Operand(this.scanner.StringValue)); NextLex(); PassToken(XPathScanner.LexKind.RParens); return new Function(pi.FType, argList); } if (this.scanner.Name == "key") { NextLex(); PassToken(XPathScanner.LexKind.LParens); CheckToken(XPathScanner.LexKind.String); argList.Add(new Operand(this.scanner.StringValue)); NextLex(); PassToken(XPathScanner.LexKind.Comma); CheckToken(XPathScanner.LexKind.String); argList.Add(new Operand(this.scanner.StringValue)); NextLex(); PassToken(XPathScanner.LexKind.RParens); return new Function("", "key", argList); } } return null; }
//>> FilterExpr ::= PrimaryExpr | FilterExpr Predicate private AstNode ParseFilterExpr(AstNode qyInput) { AstNode opnd = ParsePrimaryExpr(qyInput); while (this.scanner.Kind == XPathScanner.LexKind.LBracket) { // opnd must be a query opnd = new Filter(opnd, ParsePredicate(opnd)); } return opnd; }
//>> StepPattern ::= ChildOrAttributeAxisSpecifier NodeTest Predicate* //>> ChildOrAttributeAxisSpecifier ::= @ ? | ('child' | 'attribute') '::' private AstNode ParseStepPattern(AstNode qyInput) { AstNode opnd; Axis.AxisType axisType = Axis.AxisType.Child; switch (this.scanner.Kind) { case XPathScanner.LexKind.At: //>> '@' axisType = Axis.AxisType.Attribute; NextLex(); break; case XPathScanner.LexKind.Axe: //>> AxisName '::' axisType = GetAxis(this.scanner); if (axisType != Axis.AxisType.Child && axisType != Axis.AxisType.Attribute) { throw new XPathException(Res.Xp_InvalidToken, scanner.SourceText); } NextLex(); break; } XPathNodeType nodeType = ( axisType == Axis.AxisType.Attribute ? XPathNodeType.Attribute : /* default: */ XPathNodeType.Element ); opnd = ParseNodeTest(qyInput, axisType, nodeType); while (XPathScanner.LexKind.LBracket == this.scanner.Kind) { opnd = new Filter(opnd, ParsePredicate(opnd)); } return opnd; }
//>> Predicate ::= '[' Expr ']' private AstNode ParsePredicate(AstNode qyInput) { AstNode opnd; // we have predicates. Check that input type is NodeSet CheckNodeSet(qyInput.ReturnType); PassToken(XPathScanner.LexKind.LBracket); opnd = ParseExpresion(qyInput); PassToken(XPathScanner.LexKind.RBracket); return opnd; }
//>> LocationPath ::= RelativeLocationPath | AbsoluteLocationPath private AstNode ParseLocationPath(AstNode qyInput) { if (this.scanner.Kind == XPathScanner.LexKind.Slash) { NextLex(); AstNode opnd = new Root(); if (IsStep(this.scanner.Kind)) { opnd = ParseRelativeLocationPath(opnd); } return opnd; } else if (this.scanner.Kind == XPathScanner.LexKind.SlashSlash) { NextLex(); return ParseRelativeLocationPath(new Axis(Axis.AxisType.DescendantOrSelf, new Root())); } else { return ParseRelativeLocationPath(qyInput); } } // ParseLocationPath
//>> Step ::= '.' | '..' | ( AxisName '::' | '@' )? NodeTest Predicate* private AstNode ParseStep(AstNode qyInput) { AstNode opnd; if (XPathScanner.LexKind.Dot == this.scanner.Kind) { //>> '.' NextLex(); opnd = new Axis(Axis.AxisType.Self, qyInput); } else if (XPathScanner.LexKind.DotDot == this.scanner.Kind) { //>> '..' NextLex(); opnd = new Axis(Axis.AxisType.Parent, qyInput); } else { //>> ( AxisName '::' | '@' )? NodeTest Predicate* Axis.AxisType axisType = Axis.AxisType.Child; switch (this.scanner.Kind) { case XPathScanner.LexKind.At: //>> '@' axisType = Axis.AxisType.Attribute; NextLex(); break; case XPathScanner.LexKind.Axe: //>> AxisName '::' axisType = GetAxis(this.scanner); NextLex(); break; } XPathNodeType nodeType = ( axisType == Axis.AxisType.Attribute ? XPathNodeType.Attribute : // axisType == Axis.AxisType.Namespace ? XPathNodeType.Namespace : // No Idea why it's this way but othervise Axes doesn't work /* default: */ XPathNodeType.Element ); opnd = ParseNodeTest(qyInput, axisType, nodeType); while (XPathScanner.LexKind.LBracket == this.scanner.Kind) { opnd = new Filter(opnd, ParsePredicate(opnd)); } } return opnd; }
private static void ComposeExpression(AstNode node, StringBuilder expr) { if (node == null) return; switch (node.TypeOfAst) { case AstNode.QueryType.Axis: ComposeAxis((Axis)node, expr); break; case AstNode.QueryType.Operator: ComposeOperator((Operator)node, expr); break; case AstNode.QueryType.Filter: ComposeFilter((Filter)node, expr); break; case AstNode.QueryType.ConstantOperand: ComposeOperand((Operand)node, expr); break; case AstNode.QueryType.Variable: ComposeVariable((Variable)node, expr); break; case AstNode.QueryType.Function: ComposeFunction((Function)node, expr); break; case AstNode.QueryType.Group: ComposeGroup((Group)node, expr); break; case AstNode.QueryType.Root: ComposeRoot((Root)node, expr); break; case AstNode.QueryType.Error: Debug.Fail("Error node inside AST"); break; default: Debug.Fail("Unknown type of AST node"); break; } }
internal Function(FunctionType ftype, AstNode arg) { _functionType = ftype; _argumentList = new ArrayList(); _argumentList.Add(arg); }