public bool Validate(List <Flag> flags, CancellationToken cancel, bool isCompilerAction = false) { if (myComprData != null && myComprData.Depth > MaxDepth) { var flag = new Flag( SeverityKind.Error, AST.Node, Constants.BadSyntax.ToString( string.Format("Comprehension nesting too deep. Maximum nesting depth is {0}.", MaxDepth)), Constants.BadSyntax.Code); flags.Add(flag); return(RecordValidationResult(false)); } IEnumerable <Node> heads = null; IEnumerable <Body> bodies = null; switch (AST.Node.NodeKind) { case NodeKind.Compr: heads = ((Compr)AST.Node).Heads; bodies = ((Compr)AST.Node).Bodies; break; case NodeKind.Rule: heads = ((Rule)AST.Node).Heads; bodies = ((Rule)AST.Node).Bodies; break; default: throw new NotImplementedException(); } if (heads.IsEmpty <Node>()) { var flag = new Flag( SeverityKind.Error, AST.Node, Constants.BadSyntax.ToString("The expression has no heads."), Constants.BadSyntax.Code); flags.Add(flag); return(RecordValidationResult(false)); } //// Step 1.a. If the body is empty, treat it like a TRUE body. var result = true; if (bodies.IsEmpty <Body>()) { bodies = EnumerableMethods.GetEnumerable <Body>(MkTrueBody(heads.First <Node>().Span)); } //// Step 1.b. Otherwise, find all the variables (possibly) with selectors //// occurring in all the heads. These will be registered with the bodies. var varList = new LinkedList <Id>(); foreach (var h in heads) { FindVarLikeIds(h, varList); } //// Step 2. Expand heads / bodies. Term type; TypeEnvironment bodyEnv; foreach (var b in bodies) { bodyEnv = TypeEnvironment.AddChild(b); var cs = new ConstraintSystem(Index, b, bodyEnv, myComprData); if (!cs.Validate(flags, varList, cancel)) { result = false; continue; } foreach (var v in cs.Variables) { if (cs.TryGetType(v, out type)) { bodyEnv.SetType(v, type); } } foreach (var h in heads) { var act = new Action(h, cs, TypeEnvironment, myComprData, AST.Node); if (act.Validate(flags, cancel, isCompilerAction)) { actions.AddLast(act); } else { result = false; } if (cancel.IsCancellationRequested) { return(RecordValidationResult(false)); } } } if (result && !cancel.IsCancellationRequested) { TypeEnvironment.JoinTypes(); Contract.Assert(AST.Node.CompilerData == null); AST.Node.CompilerData = TypeEnvironment; return(RecordValidationResult(true)); } else { return(RecordValidationResult(false)); } }