private XPathExpr ParsePrimaryExpression() { XPathExpr expr = this.ParseVariableExpression(); if ((expr == null) && (this.NextToken(XPathTokenID.LParen) != null)) { expr = this.ParseExpression(); if ((expr == null) || (this.NextToken(XPathTokenID.RParen) == null)) { this.ThrowError(QueryCompileError.InvalidExpression); } } if (expr == null) { expr = this.ParseLiteralExpression(); } if (expr == null) { expr = this.ParseNumberExpression(); } if (expr == null) { expr = this.ParseFunctionExpression(); } return(expr); }
XPathExpr ParseFilterExpression() { XPathExpr primaryExpr = this.ParsePrimaryExpression(); if (null == primaryExpr) { return(null); } XPathExpr filterExpr = new XPathExpr(XPathExprType.Filter, primaryExpr.ReturnType); filterExpr.Add(primaryExpr); XPathExpr predicate = this.ParsePredicateExpression(); if (null != predicate) { EnsureReturnsNodeSet(primaryExpr); //XPathExpr filterExpr = new XPathExpr(XPathExprType.Filter, ValueDataType.Sequence); //filterExpr.Add(primaryExpr); filterExpr.Add(predicate); // Read in any additional predicates while (null != (predicate = this.ParsePredicateExpression())) { filterExpr.Add(predicate); } return(filterExpr); } return(primaryExpr); }
XPathExpr ParsePrimaryExpression() { XPathExpr expr = this.ParseVariableExpression(); if (null == expr) { if (null != this.NextToken(XPathTokenID.LParen)) { expr = this.ParseExpression(); if (null == expr || null == this.NextToken(XPathTokenID.RParen)) { this.ThrowError(QueryCompileError.InvalidExpression); } } } if (null == expr) { expr = this.ParseLiteralExpression(); } if (null == expr) { expr = this.ParseNumberExpression(); } if (null == expr) { expr = this.ParseFunctionExpression(); } return(expr); }
private void CompileFilter(XPathExpr expr) { XPathExprList subExpr = expr.SubExpr; XPathExpr expr2 = subExpr[0]; if ((subExpr.Count > 1) && (ValueDataType.Sequence != expr2.ReturnType)) { this.ThrowError(QueryCompileError.InvalidExpression); } this.CompileExpression(expr2); if (expr2.ReturnType == ValueDataType.Sequence) { if (!this.IsSpecialInternalFunction(expr2) && (expr.SubExprCount > 1)) { this.codeBlock.Append(new MergeOpcode()); this.codeBlock.Append(new PopSequenceToSequenceStackOpcode()); } else if (this.IsSpecialInternalFunction(expr2) && (expr.SubExprCount > 1)) { this.codeBlock.DetachLast(); } this.compiler.nestingLevel++; if (this.compiler.nestingLevel > 3) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(QueryCompileError.PredicateNestingTooDeep)); } for (int i = 1; i < expr.SubExprCount; i++) { this.CompilePredicate(subExpr[i]); } this.compiler.nestingLevel--; } }
private XPathExpr ParseFilterExpression() { XPathExpr expr = this.ParsePrimaryExpression(); if (expr == null) { return(null); } XPathExpr expr2 = new XPathExpr(XPathExprType.Filter, expr.ReturnType); expr2.Add(expr); XPathExpr expr3 = this.ParsePredicateExpression(); if (expr3 == null) { return(expr); } this.EnsureReturnsNodeSet(expr); expr2.Add(expr3); while ((expr3 = this.ParsePredicateExpression()) != null) { expr2.Add(expr3); } return(expr2); }
private void CompileXsltFunction(XPathXsltFunctionExpr expr) { if (expr.SubExprCount > 0) { XPathExprList subExpr = expr.SubExpr; for (int i = subExpr.Count - 1; i >= 0; i--) { XPathExpr expr2 = subExpr[i]; this.CompileExpression(expr2); ValueDataType destType = XPathXsltFunctionExpr.ConvertTypeFromXslt(expr.Function.ArgTypes[i]); if ((destType != ValueDataType.None) && (expr2.ReturnType != destType)) { this.CompileTypecast(destType); } } } if (expr.Function is XPathMessageFunction) { this.codeBlock.Append(new XPathMessageFunctionCallOpcode((XPathMessageFunction)expr.Function, expr.SubExprCount)); if (this.IsSpecialInternalFunction(expr)) { this.codeBlock.Append(new PopSequenceToValueStackOpcode()); } } else { this.codeBlock.Append(new XsltFunctionCallOpcode(expr.Context, expr.Function, expr.SubExprCount)); } }
// Compiles expressions at nesting level == 1 -> boolean expressions that can be processed // with less complex opcodes because they will never track multiple sequences simultaneously void CompileBasicBoolean(XPathExpr expr, bool testValue) { // Boolean expressions must always have at least 2 sub expressions Fx.Assert(expr.SubExprCount > 1, ""); Fx.Assert(this.compiler.nestingLevel == 1, ""); OpcodeBlock boolBlock = new OpcodeBlock(); // struct Opcode blockEnd = new BlockEndOpcode(); XPathExprList subExprList = expr.SubExpr; // Compile sub-expressions for (int i = 0; i < subExprList.Count; ++i) { XPathExpr subExpr = subExprList[i]; boolBlock.Append(this.CompileBlock(subExpr)); // Make sure each sub-expression can produce a boolean result if (subExpr.ReturnType != ValueDataType.Boolean) { boolBlock.Append(new TypecastOpcode(ValueDataType.Boolean)); } if (i < (subExprList.Count - 1)) { // No point jumping if this is the last expression boolBlock.Append(new JumpIfOpcode(blockEnd, testValue)); } } boolBlock.Append(blockEnd); this.codeBlock.Append(boolBlock); }
private void CompileLiteralOrdinal(XPathExpr expr) { int ordinal = 0; try { XPathNumberExpr expr2 = (XPathNumberExpr)expr; ordinal = Convert.ToInt32(expr2.Number); if (expr2.Negate) { ordinal = -ordinal; expr2.Negate = false; } if (ordinal < 1) { this.ThrowError(QueryCompileError.InvalidOrdinal); } } catch (OverflowException) { this.ThrowError(QueryCompileError.InvalidOrdinal); } if ((this.compiler.flags & QueryCompilerFlags.InverseQuery) != QueryCompilerFlags.None) { this.codeBlock.Append(new PushContextPositionOpcode()); this.codeBlock.Append(new NumberEqualsOpcode((double)ordinal)); } else { this.codeBlock.Append(new LiteralOrdinalOpcode(ordinal)); } }
internal static OpcodeBlock CompileForInternalEngine(string xpath, XmlNamespaceManager nsManager, QueryCompilerFlags flags, IFunctionLibrary[] functionLibs, out ValueDataType returnType) { OpcodeBlock codeBlock; returnType = ValueDataType.None; if (0 == xpath.Length) { // 0 length XPaths always match codeBlock = new OpcodeBlock(); codeBlock.Append(new PushBooleanOpcode(true)); // Always match by pushing true on the eval stack } else { // Try to parse the xpath. Bind to default function libraries // The parser returns an expression tree XPathParser parser = new XPathParser(xpath, nsManager, functionLibs); XPathExpr parseTree = parser.Parse(); if (null == parseTree) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(QueryCompileError.CouldNotParseExpression)); } returnType = parseTree.ReturnType; // Compile the expression tree XPathCompiler compiler = new XPathCompiler(flags); codeBlock = compiler.Compile(parseTree); } return(codeBlock); }
void CompileXsltFunction(XPathXsltFunctionExpr expr) { // Compile each argument expression first, introducing a typecast where appropriate // Arguments are pushed C style - right to left if (expr.SubExprCount > 0) { XPathExprList paramList = expr.SubExpr; for (int i = paramList.Count - 1; i >= 0; --i) { XPathExpr param = paramList[i]; this.CompileExpression(param); ValueDataType paramType = XPathXsltFunctionExpr.ConvertTypeFromXslt(expr.Function.ArgTypes[i]); if (ValueDataType.None != paramType) { if (param.ReturnType != paramType) { this.CompileTypecast(paramType); } } } } if (expr.Function is XPathMessageFunction) { this.codeBlock.Append(new XPathMessageFunctionCallOpcode((XPathMessageFunction)expr.Function, expr.SubExprCount)); if (IsSpecialInternalFunction(expr)) { this.codeBlock.Append(new PopSequenceToValueStackOpcode()); } } else { this.codeBlock.Append(new XsltFunctionCallOpcode(expr.Context, expr.Function, expr.SubExprCount)); } }
void CompileRelativePath(XPathExpr expr, bool start) { Fx.Assert(XPathExprType.RelativePath == expr.Type, ""); this.CompileSteps(expr.SubExpr, start); // Step complete. Transfer results onto the value stack this.codeBlock.Append(new PopSequenceToValueStackOpcode()); }
private void CompileBoolean(XPathExpr expr, bool testValue) { if (this.compiler.nestingLevel == 1) { this.CompileBasicBoolean(expr, testValue); } else { OpcodeBlock block = new OpcodeBlock(); Opcode jump = new BlockEndOpcode(); block.Append(new PushBooleanOpcode(testValue)); XPathExprList subExpr = expr.SubExpr; XPathExpr expr2 = subExpr[0]; block.Append(this.CompileBlock(expr2)); if (expr2.ReturnType != ValueDataType.Boolean) { block.Append(new TypecastOpcode(ValueDataType.Boolean)); } block.Append(new ApplyBooleanOpcode(jump, testValue)); for (int i = 1; i < subExpr.Count; i++) { expr2 = subExpr[i]; block.Append(new StartBooleanOpcode(testValue)); block.Append(this.CompileBlock(expr2)); if (expr2.ReturnType != ValueDataType.Boolean) { block.Append(new TypecastOpcode(ValueDataType.Boolean)); } block.Append(new EndBooleanOpcode(jump, testValue)); } block.Append(jump); this.codeBlock.Append(block); } }
private void CompileBoolean(XPathExpr expr, bool testValue) { if (this.compiler.nestingLevel == 1) { this.CompileBasicBoolean(expr, testValue); } else { OpcodeBlock block = new OpcodeBlock(); Opcode jump = new BlockEndOpcode(); block.Append(new PushBooleanOpcode(testValue)); XPathExprList subExpr = expr.SubExpr; XPathExpr expr2 = subExpr[0]; block.Append(this.CompileBlock(expr2)); if (expr2.ReturnType != ValueDataType.Boolean) { block.Append(new TypecastOpcode(ValueDataType.Boolean)); } block.Append(new ApplyBooleanOpcode(jump, testValue)); for (int i = 1; i < subExpr.Count; i++) { expr2 = subExpr[i]; block.Append(new StartBooleanOpcode(testValue)); block.Append(this.CompileBlock(expr2)); if (expr2.ReturnType != ValueDataType.Boolean) { block.Append(new TypecastOpcode(ValueDataType.Boolean)); } block.Append(new EndBooleanOpcode(jump, testValue)); } block.Append(jump); this.codeBlock.Append(block); } }
private void TypecastIfRequired(XPathExpr expr) { if (expr.TypecastRequired) { expr.TypecastRequired = false; this.CompileTypecast(expr.ReturnType); } }
XPathExpr EnsureReturnsNodeSet(XPathExpr expr) { if (expr.ReturnType != ValueDataType.Sequence) { this.ThrowError(QueryCompileError.InvalidFunction); } return(expr); }
XPathExpr EnsureReturnsNodeSet(XPathExpr expr) { if (expr.ReturnType != ValueDataType.Sequence) { this.ThrowError(QueryCompileError.InvalidFunction); } return expr; }
private XPathExpr ParseFunctionExpression() { XPathExpr expr; XPathToken token = this.NextToken(XPathTokenID.Function); if (token == null) { return(null); } NodeQName name = this.QualifyName(token.Prefix, token.Name); this.NextToken(XPathTokenID.LParen, QueryCompileError.InvalidFunction); XPathExprList args = new XPathExprList(); while ((expr = this.ParseExpression()) != null) { args.Add(expr); if (this.NextToken(XPathTokenID.Comma) == null) { break; } } XPathExpr expr2 = null; if (this.functionLibraries != null) { QueryFunction function = null; for (int i = 0; i < this.functionLibraries.Length; i++) { function = this.functionLibraries[i].Bind(name.Name, name.Namespace, args); if (function != null) { expr2 = new XPathFunctionExpr(function, args); break; } } } if ((expr2 == null) && (this.context != null)) { XPathResultType[] argTypes = new XPathResultType[args.Count]; for (int j = 0; j < args.Count; j++) { argTypes[j] = XPathXsltFunctionExpr.ConvertTypeToXslt(args[j].ReturnType); } string prefix = this.context.LookupPrefix(name.Namespace); IXsltContextFunction function2 = this.context.ResolveFunction(prefix, name.Name, argTypes); if (function2 != null) { expr2 = new XPathXsltFunctionExpr(this.context, function2, args); } } if (expr2 == null) { this.ThrowError(QueryCompileError.UnsupportedFunction); } this.NextToken(XPathTokenID.RParen, QueryCompileError.InvalidFunction); return(expr2); }
internal XPathConjunctExpr(XPathExprType type, ValueDataType returnType, XPathExpr left, XPathExpr right) : base(type, returnType) { if ((left == null) || (right == null)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(QueryCompileError.InvalidExpression)); } base.SubExpr.Add(left); base.SubExpr.Add(right); }
internal XPathConjunctExpr(XPathExprType type, ValueDataType returnType, XPathExpr left, XPathExpr right) : base(type, returnType) { if ((left == null) || (right == null)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(QueryCompileError.InvalidExpression)); } base.SubExpr.Add(left); base.SubExpr.Add(right); }
private void NegateIfRequired(XPathExpr expr) { this.TypecastIfRequired(expr); if (expr.Negate) { expr.Negate = false; this.codeBlock.Append(new NegateOpcode()); } }
void NegateIfRequired(XPathExpr expr) { // We can combine these two since the flags they examine are set in exactly one (the same) place. TypecastIfRequired(expr); if (expr.Negate) { expr.Negate = false; this.codeBlock.Append(new NegateOpcode()); } }
private void CompileLocationPath(XPathExpr expr) { XPathStepExpr expr2 = (XPathStepExpr)expr.SubExpr[0]; this.CompileSteps(expr.SubExpr); if (1 == this.compiler.nestingLevel) { this.compiler.SetPushInitialContext(expr2.SelectDesc.Type != QueryNodeType.Root); } }
XPathExpr ParseRelationalExpression() { XPathExpr leftExpr = this.ParseAdditiveExpression(); if (null != leftExpr) { RelationOperator op; do { op = RelationOperator.None; XPathToken token = this.NextToken(); if (null != token) { switch (token.TokenID) { default: this.PushToken(token); break; case XPathTokenID.Lt: op = RelationOperator.Lt; break; case XPathTokenID.Lte: op = RelationOperator.Le; break; case XPathTokenID.Gt: op = RelationOperator.Gt; break; case XPathTokenID.Gte: op = RelationOperator.Ge; break; } if (RelationOperator.None != op) { XPathExpr rightExpr = this.ParseAdditiveExpression(); if (null == rightExpr) { this.ThrowError(QueryCompileError.InvalidExpression); } leftExpr = new XPathRelationExpr(op, leftExpr, rightExpr); } } } while (RelationOperator.None != op); } return(leftExpr); }
XPathExpr ParsePathExpression() { XPathExpr pathExpr = this.ParseLocationPath(); if (null != pathExpr) { return(pathExpr); } // Perhaps we have a filter expression XPathExpr filterExpr = this.ParseFilterExpression(); if (null != filterExpr) { if (null != this.NextToken(XPathTokenID.Slash)) { EnsureReturnsNodeSet(filterExpr); // Is this a complex filter expression.. i.e. followed by further selections.. XPathExprList relPath = this.ParseRelativePath(); if (null == relPath) { this.ThrowError(QueryCompileError.InvalidLocationPath); } XPathExpr relPathExpr = new XPathExpr(XPathExprType.RelativePath, ValueDataType.Sequence, relPath); pathExpr = new XPathExpr(XPathExprType.Path, ValueDataType.Sequence); pathExpr.Add(filterExpr); pathExpr.Add(relPathExpr); } else if (null != this.NextToken(XPathTokenID.DblSlash)) { EnsureReturnsNodeSet(filterExpr); XPathExprList relPath = this.ParseRelativePath(); if (null == relPath) { this.ThrowError(QueryCompileError.InvalidLocationPath); } XPathExpr relPathExpr = new XPathExpr(XPathExprType.RelativePath, ValueDataType.Sequence, relPath); pathExpr = new XPathExpr(XPathExprType.Path, ValueDataType.Sequence); pathExpr.Add(filterExpr); pathExpr.Add(new XPathStepExpr(new NodeSelectCriteria(QueryAxisType.DescendantOrSelf, NodeQName.Empty, QueryNodeType.All))); pathExpr.Add(relPathExpr); } else { pathExpr = filterExpr; } } return(pathExpr); }
void CompileLocationPath(XPathExpr expr) { Fx.Assert(expr.SubExprCount > 0, ""); XPathStepExpr firstStep = (XPathStepExpr)expr.SubExpr[0]; this.CompileSteps(expr.SubExpr); if (1 == this.compiler.nestingLevel) { this.compiler.SetPushInitialContext(firstStep.SelectDesc.Type != QueryNodeType.Root); } }
XPathExpr ParseMultiplicativeExpression() { XPathExpr leftExpr = this.ParseUnaryExpression(); if (null != leftExpr) { MathOperator op; do { op = MathOperator.None; XPathToken token = this.NextToken(); if (null != token) { switch (token.TokenID) { default: this.PushToken(token); break; case XPathTokenID.Multiply: op = MathOperator.Multiply; break; case XPathTokenID.Div: op = MathOperator.Div; break; case XPathTokenID.Mod: op = MathOperator.Mod; break; } if (MathOperator.None != op) { XPathExpr rightExpr = this.ParseUnaryExpression(); if (null == rightExpr) { this.ThrowError(QueryCompileError.InvalidExpression); } leftExpr = new XPathMathExpr(op, leftExpr, rightExpr); } } } while (MathOperator.None != op); } return(leftExpr); }
internal XPathExpr Parse() { XPathExpr expr = this.ParseExpression(); if (expr == null) { this.ThrowError(QueryCompileError.InvalidExpression); } if (this.NextToken() != null) { this.ThrowError(QueryCompileError.UnexpectedToken); } return(expr); }
private void CompileFunctionParam(QueryFunction function, XPathExprList paramList, int index) { XPathExpr expr = paramList[index]; this.CompileExpression(expr); if ((function.ParamTypes[index] != ValueDataType.None) && (expr.ReturnType != function.ParamTypes[index])) { if (function.ParamTypes[index] == ValueDataType.Sequence) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(QueryCompileError.InvalidTypeConversion)); } this.CompileTypecast(function.ParamTypes[index]); } }
private bool IsSpecialInternalFunction(XPathExpr expr) { if (expr.Type != XPathExprType.XsltFunction) { return(false); } XPathMessageFunction function = ((XPathXsltFunctionExpr)expr).Function as XPathMessageFunction; if (function == null) { return(false); } return((function.ReturnType == XPathResultType.NodeSet) && (function.Maxargs == 0)); }
private XPathExpr ParseRelationalExpression() { XPathExpr left = this.ParseAdditiveExpression(); if (left != null) { RelationOperator none; do { none = RelationOperator.None; XPathToken token = this.NextToken(); if (token != null) { switch (token.TokenID) { case XPathTokenID.Gt: none = RelationOperator.Gt; break; case XPathTokenID.Gte: none = RelationOperator.Ge; break; case XPathTokenID.Lt: none = RelationOperator.Lt; break; case XPathTokenID.Lte: none = RelationOperator.Le; break; default: this.PushToken(token); break; } if (none != RelationOperator.None) { XPathExpr right = this.ParseAdditiveExpression(); if (right == null) { this.ThrowError(QueryCompileError.InvalidExpression); } left = new XPathRelationExpr(none, left, right); } } }while (none != RelationOperator.None); } return(left); }
internal virtual OpcodeBlock Compile(XPathExpr expr) { this.nestingLevel = 1; this.pushInitialContext = false; OpcodeBlock block = new XPathExprCompiler(this).Compile(expr); if (this.pushInitialContext) { OpcodeBlock block2 = new OpcodeBlock(); block2.Append(new PushContextNodeOpcode()); block2.Append(block); block2.Append(new PopContextNodes()); return block2; } return block; }
internal void AddBooleanExpression(XPathExprType boolExprType, XPathExpr expr) { if (boolExprType == expr.Type) { XPathExprList subExpr = expr.SubExpr; for (int i = 0; i < subExpr.Count; i++) { this.AddBooleanExpression(boolExprType, subExpr[i]); } } else { this.Add(expr); } }
private XPathExpr ParsePredicateExpression() { XPathExpr expr = null; if (this.NextToken(XPathTokenID.LBracket) != null) { expr = this.ParseExpression(); if (expr == null) { this.ThrowError(QueryCompileError.InvalidPredicate); } this.NextToken(XPathTokenID.RBracket, QueryCompileError.InvalidPredicate); } return(expr); }
internal void AddBooleanExpression(XPathExprType boolExprType, XPathExpr expr) { if (boolExprType == expr.Type) { XPathExprList subExpr = expr.SubExpr; for (int i = 0; i < subExpr.Count; i++) { this.AddBooleanExpression(boolExprType, subExpr[i]); } } else { this.Add(expr); } }
private void CompilePath(XPathExpr expr) { if (expr.Type == XPathExprType.Filter) { this.CompileFilter(expr.SubExpr[0]); } else { this.CompileExpression(expr.SubExpr[0]); if (expr.SubExpr[0].ReturnType == ValueDataType.Sequence) { if (this.IsSpecialInternalFunction(expr.SubExpr[0])) { this.codeBlock.DetachLast(); } else { this.codeBlock.Append(new MergeOpcode()); this.codeBlock.Append(new PopSequenceToSequenceStackOpcode()); } } } if (expr.SubExprCount == 2) { this.CompileRelativePath(expr.SubExpr[1], false); } else if (expr.SubExprCount == 3) { XPathExpr expr2 = expr.SubExpr[1]; XPathStepExpr expr3 = (XPathStepExpr)expr2; if (!expr3.SelectDesc.Axis.IsSupported()) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(QueryCompileError.UnsupportedAxis)); } this.codeBlock.Append(new SelectOpcode(expr3.SelectDesc)); if (expr3.SubExprCount > 0) { this.compiler.nestingLevel++; if (this.compiler.nestingLevel > 3) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(QueryCompileError.PredicateNestingTooDeep)); } this.CompilePredicates(expr3.SubExpr); this.compiler.nestingLevel--; } this.CompileRelativePath(expr.SubExpr[2], false); } }
// Compiles top level expressions internal virtual OpcodeBlock Compile(XPathExpr expr) { Fx.Assert(null != expr, ""); this.nestingLevel = 1; this.pushInitialContext = false; XPathExprCompiler exprCompiler = new XPathExprCompiler(this); OpcodeBlock mainBlock = exprCompiler.Compile(expr); if (this.pushInitialContext) { OpcodeBlock expandedBlock = new OpcodeBlock(); expandedBlock.Append(new PushContextNodeOpcode()); expandedBlock.Append(mainBlock); expandedBlock.Append(new PopContextNodes()); return expandedBlock; } return mainBlock; }
internal OpcodeBlock Compile(XPathExpr expr) { this.codeBlock = new OpcodeBlock(); // struct this.CompileExpression(expr); return this.codeBlock; }
void CompileRelativePath(XPathExpr expr, bool start) { Fx.Assert(XPathExprType.RelativePath == expr.Type, ""); this.CompileSteps(expr.SubExpr, start); // Step complete. Transfer results onto the value stack this.codeBlock.Append(new PopSequenceToValueStackOpcode()); }
void CompilePredicate(XPathExpr expr) { // If the expression does not return a boolean, introduce a typecast // If the predicate expression is a standalone number literal, interpret it as a literal if (expr.IsLiteral && XPathExprType.Number == expr.Type) { this.CompileLiteralOrdinal(expr); } else { this.CompileExpression(expr); if (expr.ReturnType == ValueDataType.Double) { this.codeBlock.Append(new OrdinalOpcode()); } else if (expr.ReturnType != ValueDataType.Boolean) { this.CompileTypecast(ValueDataType.Boolean); } } // Apply the results of the predicate on the context sequence this.codeBlock.Append(new ApplyFilterOpcode()); }
XPathExpr ParseAndExpression() { XPathExpr eqExpr = this.ParseEqualityExpression(); if (null != eqExpr && null != this.NextToken(XPathTokenID.And)) { XPathExpr andExpr = new XPathExpr(XPathExprType.And, ValueDataType.Boolean); andExpr.AddBooleanExpression(XPathExprType.And, eqExpr); do { eqExpr = this.ParseEqualityExpression(); if (eqExpr == null) this.ThrowError(QueryCompileError.InvalidExpression); andExpr.AddBooleanExpression(XPathExprType.And, eqExpr); } while (null != this.NextToken(XPathTokenID.And)); return andExpr; } return eqExpr; }
internal void Add(XPathExpr expr) { Fx.Assert(null != expr, ""); this.list.Add(expr); }
XPathExpr ParsePathExpression() { XPathExpr pathExpr = this.ParseLocationPath(); if (null != pathExpr) { return pathExpr; } // Perhaps we have a filter expression XPathExpr filterExpr = this.ParseFilterExpression(); if (null != filterExpr) { if (null != this.NextToken(XPathTokenID.Slash)) { EnsureReturnsNodeSet(filterExpr); // Is this a complex filter expression.. i.e. followed by further selections.. XPathExprList relPath = this.ParseRelativePath(); if (null == relPath) { this.ThrowError(QueryCompileError.InvalidLocationPath); } XPathExpr relPathExpr = new XPathExpr(XPathExprType.RelativePath, ValueDataType.Sequence, relPath); pathExpr = new XPathExpr(XPathExprType.Path, ValueDataType.Sequence); pathExpr.Add(filterExpr); pathExpr.Add(relPathExpr); } else if (null != this.NextToken(XPathTokenID.DblSlash)) { EnsureReturnsNodeSet(filterExpr); XPathExprList relPath = this.ParseRelativePath(); if (null == relPath) { this.ThrowError(QueryCompileError.InvalidLocationPath); } XPathExpr relPathExpr = new XPathExpr(XPathExprType.RelativePath, ValueDataType.Sequence, relPath); pathExpr = new XPathExpr(XPathExprType.Path, ValueDataType.Sequence); pathExpr.Add(filterExpr); pathExpr.Add(new XPathStepExpr(new NodeSelectCriteria(QueryAxisType.DescendantOrSelf, NodeQName.Empty, QueryNodeType.All))); pathExpr.Add(relPathExpr); } else { pathExpr = filterExpr; } } return pathExpr; }
OpcodeBlock CompileBlock(XPathExpr expr) { XPathExprCompiler compiler = new XPathExprCompiler(this); return compiler.Compile(expr); }
bool IsSpecialInternalFunction(XPathExpr expr) { if (expr.Type != XPathExprType.XsltFunction) { return false; } XPathMessageFunction func = ((XPathXsltFunctionExpr)expr).Function as XPathMessageFunction; if (func != null) { return func.ReturnType == XPathResultType.NodeSet && func.Maxargs == 0; } return false; }
XPathExpr ParseOrExpression() { XPathExpr andExpr = this.ParseAndExpression(); if (null != andExpr && null != this.NextToken(XPathTokenID.Or)) { XPathExpr orExpr = new XPathExpr(XPathExprType.Or, ValueDataType.Boolean); orExpr.AddBooleanExpression(XPathExprType.Or, andExpr); do { andExpr = this.ParseAndExpression(); if (andExpr == null) this.ThrowError(QueryCompileError.InvalidExpression); orExpr.AddBooleanExpression(XPathExprType.Or, andExpr); } while (null != this.NextToken(XPathTokenID.Or)); return orExpr; } return andExpr; }
XPathExpr ParseFilterExpression() { XPathExpr primaryExpr = this.ParsePrimaryExpression(); if (null == primaryExpr) { return null; } XPathExpr filterExpr = new XPathExpr(XPathExprType.Filter, primaryExpr.ReturnType); filterExpr.Add(primaryExpr); XPathExpr predicate = this.ParsePredicateExpression(); if (null != predicate) { EnsureReturnsNodeSet(primaryExpr); //XPathExpr filterExpr = new XPathExpr(XPathExprType.Filter, ValueDataType.Sequence); //filterExpr.Add(primaryExpr); filterExpr.Add(predicate); // Read in any additional predicates while (null != (predicate = this.ParsePredicateExpression())) { filterExpr.Add(predicate); } return filterExpr; } return primaryExpr; }
// Compiles expressions at nesting level == 1 -> boolean expressions that can be processed // with less complex opcodes because they will never track multiple sequences simultaneously void CompileBasicBoolean(XPathExpr expr, bool testValue) { // Boolean expressions must always have at least 2 sub expressions Fx.Assert(expr.SubExprCount > 1, ""); Fx.Assert(this.compiler.nestingLevel == 1, ""); OpcodeBlock boolBlock = new OpcodeBlock(); // struct Opcode blockEnd = new BlockEndOpcode(); XPathExprList subExprList = expr.SubExpr; // Compile sub-expressions for (int i = 0; i < subExprList.Count; ++i) { XPathExpr subExpr = subExprList[i]; boolBlock.Append(this.CompileBlock(subExpr)); // Make sure each sub-expression can produce a boolean result if (subExpr.ReturnType != ValueDataType.Boolean) { boolBlock.Append(new TypecastOpcode(ValueDataType.Boolean)); } if (i < (subExprList.Count - 1)) { // No point jumping if this is the last expression boolBlock.Append(new JumpIfOpcode(blockEnd, testValue)); } } boolBlock.Append(blockEnd); this.codeBlock.Append(boolBlock); }
internal void Add(XPathExpr expr) { this.list.Add(expr); }
internal XPathRelationExpr(RelationOperator op, XPathExpr left, XPathExpr right) : base(XPathExprType.Relational, ValueDataType.Boolean, left, right) { this.op = op; }
void NegateIfRequired(XPathExpr expr) { // We can combine these two since the flags they examine are set in exactly one (the same) place. TypecastIfRequired(expr); if (expr.Negate) { expr.Negate = false; this.codeBlock.Append(new NegateOpcode()); } }
void TypecastIfRequired(XPathExpr expr) { if (expr.TypecastRequired) { expr.TypecastRequired = false; CompileTypecast(expr.ReturnType); } }
void CompileLiteralOrdinal(XPathExpr expr) { int ordinal = 0; try { XPathNumberExpr numExpr = (XPathNumberExpr)expr; ordinal = Convert.ToInt32(numExpr.Number); if (numExpr.Negate) { ordinal = -ordinal; numExpr.Negate = false; } if (ordinal < 1) { this.ThrowError(QueryCompileError.InvalidOrdinal); } } catch (OverflowException) { this.ThrowError(QueryCompileError.InvalidOrdinal); } if (0 != (this.compiler.flags & QueryCompilerFlags.InverseQuery)) { this.codeBlock.Append(new PushContextPositionOpcode()); this.codeBlock.Append(new NumberEqualsOpcode(ordinal)); } else { this.codeBlock.Append(new LiteralOrdinalOpcode(ordinal)); } }
void CompileBoolean(XPathExpr expr, bool testValue) { // Boolean expressions must always have at least 2 sub expressions Fx.Assert(expr.SubExprCount > 1, ""); if (this.compiler.nestingLevel == 1) { this.CompileBasicBoolean(expr, testValue); return; } OpcodeBlock boolBlock = new OpcodeBlock(); // struct Opcode blockEnd = new BlockEndOpcode(); // Set up the result mask boolBlock.Append(new PushBooleanOpcode(testValue)); XPathExprList subExprList = expr.SubExpr; XPathExpr subExpr; // the first expression needs the least work.. subExpr = subExprList[0]; boolBlock.Append(this.CompileBlock(subExpr)); if (subExpr.ReturnType != ValueDataType.Boolean) { boolBlock.Append(new TypecastOpcode(ValueDataType.Boolean)); } boolBlock.Append(new ApplyBooleanOpcode(blockEnd, testValue)); // Compile remaining sub-expressions for (int i = 1; i < subExprList.Count; ++i) { subExpr = subExprList[i]; boolBlock.Append(new StartBooleanOpcode(testValue)); boolBlock.Append(this.CompileBlock(subExpr)); // Make sure each sub-expression can produce a boolean result if (subExpr.ReturnType != ValueDataType.Boolean) { boolBlock.Append(new TypecastOpcode(ValueDataType.Boolean)); } boolBlock.Append(new EndBooleanOpcode(blockEnd, testValue)); } boolBlock.Append(blockEnd); this.codeBlock.Append(boolBlock); }
void CompileLocationPath(XPathExpr expr) { Fx.Assert(expr.SubExprCount > 0, ""); XPathStepExpr firstStep = (XPathStepExpr)expr.SubExpr[0]; this.CompileSteps(expr.SubExpr); if (1 == this.compiler.nestingLevel) { this.compiler.SetPushInitialContext(firstStep.SelectDesc.Type != QueryNodeType.Root); } }
internal void AddBooleanExpression(XPathExprType boolExprType, XPathExpr expr) { Fx.Assert(boolExprType == this.type, ""); // An boolean sub0expression that is of the same type as its container should be merged and flattened // into its parent if (boolExprType == expr.Type) { XPathExprList subExprList = expr.SubExpr; for (int i = 0; i < subExprList.Count; ++i) { this.AddBooleanExpression(boolExprType, subExprList[i]); } } else { this.Add(expr); } }
void CompilePath(XPathExpr expr) { Fx.Assert(expr.SubExprCount == 2 || expr.SubExprCount == 3, ""); if (expr.Type == XPathExprType.Filter) { this.CompileFilter(expr.SubExpr[0]); } else { this.CompileExpression(expr.SubExpr[0]); if (expr.SubExpr[0].ReturnType == ValueDataType.Sequence) { if (IsSpecialInternalFunction(expr.SubExpr[0])) { this.codeBlock.DetachLast(); } else { this.codeBlock.Append(new MergeOpcode()); this.codeBlock.Append(new PopSequenceToSequenceStackOpcode()); } } } if (expr.SubExprCount == 2) { this.CompileRelativePath(expr.SubExpr[1], false); } else if (expr.SubExprCount == 3) { // Compile the step XPathExpr e = expr.SubExpr[1]; Fx.Assert(XPathExprType.PathStep == e.Type, ""); XPathStepExpr step = (XPathStepExpr)e; Fx.Assert(QueryNodeType.Root != step.SelectDesc.Type, ""); if (!step.SelectDesc.Axis.IsSupported()) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(QueryCompileError.UnsupportedAxis)); } this.codeBlock.Append(new SelectOpcode(step.SelectDesc)); // The step may have predicates.. if (step.SubExprCount > 0) { this.compiler.nestingLevel++; if (this.compiler.nestingLevel > 3) // throw if we find something deepter than [ [ ] ] { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(QueryCompileError.PredicateNestingTooDeep)); } this.CompilePredicates(step.SubExpr); this.compiler.nestingLevel--; } // Compile the relative path this.CompileRelativePath(expr.SubExpr[2], false); } }
void CompileExpression(XPathExpr expr) { Fx.Assert(null != expr, ""); switch (expr.Type) { default: this.ThrowError(QueryCompileError.UnsupportedExpression); break; case XPathExprType.And: this.CompileBoolean(expr, true); break; case XPathExprType.Or: this.CompileBoolean(expr, false); break; case XPathExprType.Relational: this.CompileRelational((XPathRelationExpr)expr); break; case XPathExprType.Function: this.CompileFunction((XPathFunctionExpr)expr); break; case XPathExprType.Union: { XPathConjunctExpr unionExpr = (XPathConjunctExpr)expr; this.CompileExpression(unionExpr.Left); this.CompileExpression(unionExpr.Right); this.codeBlock.Append(new UnionOpcode()); } break; case XPathExprType.RelativePath: this.CompileRelativePath(expr, true); break; case XPathExprType.LocationPath: if (expr.SubExprCount > 0) { this.CompileLocationPath(expr); // Step complete. Transfer results onto the value stack this.codeBlock.Append(new PopSequenceToValueStackOpcode()); } break; case XPathExprType.Math: this.CompileMath((XPathMathExpr)expr); break; case XPathExprType.Number: XPathNumberExpr number = (XPathNumberExpr)expr; double literal = number.Number; if (number.Negate) { number.Negate = false; literal = -literal; } this.codeBlock.Append(new PushNumberOpcode(literal)); break; case XPathExprType.String: this.codeBlock.Append(new PushStringOpcode(((XPathStringExpr)expr).String)); break; case XPathExprType.Filter: this.CompileFilter(expr); if (expr.ReturnType == ValueDataType.Sequence) { this.codeBlock.Append(new PopSequenceToValueStackOpcode()); } break; case XPathExprType.Path: this.CompilePath(expr); if (expr.SubExprCount == 0 && expr.ReturnType == ValueDataType.Sequence) { this.codeBlock.Append(new PopSequenceToValueStackOpcode()); } break; case XPathExprType.XsltFunction: this.CompileXsltFunction((XPathXsltFunctionExpr)expr); break; case XPathExprType.XsltVariable: this.CompileXsltVariable((XPathXsltVariableExpr)expr); break; } NegateIfRequired(expr); }
internal void Add(XPathExpr expr) { this.SubExpr.Add(expr); }
void CompileFilter(XPathExpr expr) { Fx.Assert(XPathExprType.Filter == expr.Type, ""); // The filter expression has two components - the expression and its predicate // It may have an optional relative path following it //Debug.Assert(expr.SubExprCount <= 3); XPathExprList subExpr = expr.SubExpr; XPathExpr filterExpr = subExpr[0]; if (subExpr.Count > 1 && ValueDataType.Sequence != filterExpr.ReturnType) { this.ThrowError(QueryCompileError.InvalidExpression); } // The filter expression will return a sequence and push it onto the value stack // Transfer it back to the sequence stack, so we can keep working on it this.CompileExpression(filterExpr); if (filterExpr.ReturnType == ValueDataType.Sequence) { if (!IsSpecialInternalFunction(filterExpr) && expr.SubExprCount > 1) { // Flatten the sequence and move it to the sequence stack this.codeBlock.Append(new MergeOpcode()); this.codeBlock.Append(new PopSequenceToSequenceStackOpcode()); } else if (IsSpecialInternalFunction(filterExpr) && expr.SubExprCount > 1) { this.codeBlock.DetachLast(); } // Now, apply the predicates this.compiler.nestingLevel++; if (this.compiler.nestingLevel > 3) // throw if we find something deepter than [ [ ] ] { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(QueryCompileError.PredicateNestingTooDeep)); } for (int i = 1; i < expr.SubExprCount; ++i) { this.CompilePredicate(subExpr[i]); } this.compiler.nestingLevel--; } }
internal XPathMathExpr(MathOperator op, XPathExpr left, XPathExpr right) : base(XPathExprType.Math, ValueDataType.Double, left, right) { this.op = op; }