/// <summary> /// Finds the first scoped variable matching the name, using Rule as the current rule to work backwards from /// </summary> public Rule FindVariable(string name, Node rule) { var previousNode = rule; foreach (var frame in Frames) { var v = frame.Variable(name, null); if (v) { return(v); } previousNode = frame; } Rule result = null; if (Parent != null) { result = Parent.FindVariable(name, rule); } if (result != null) { return(result); } if (ClosureEnvironment != null) { return(ClosureEnvironment.FindVariable(name, rule)); } return(null); }
/// <summary> /// Finds the first Ruleset matching the selector argument that inherits from or is of type TRuleset (pass this as Ruleset if /// you are trying to find ANY Ruleset that matches the selector) /// </summary> public IEnumerable <Closure> FindRulesets(Selector selector) { var matchingRuleSets = Frames .Select(frame => frame.Find <Ruleset>(this, selector, null)) .Select( matchedClosuresList => matchedClosuresList.Where( matchedClosure => { if (!Frames.Any(frame => frame.IsEqualOrClonedFrom(matchedClosure.Ruleset))) { return(true); } var mixinDef = matchedClosure.Ruleset as MixinDefinition; if (mixinDef != null) { return(mixinDef.Condition != null); } return(false); } ) ) .FirstOrDefault(matchedClosuresList => matchedClosuresList.Count() != 0); if (matchingRuleSets != null) { return(matchingRuleSets); } if (Parent != null) { matchingRuleSets = Parent.FindRulesets(selector); } if (matchingRuleSets != null) { return(matchingRuleSets); } if (ClosureEnvironment != null) { return(ClosureEnvironment.FindRulesets(selector)); } return(null); }
/// <summary> /// Finds the first Ruleset matching the selector argument that inherits from or is of type TRuleset (pass this as Ruleset if /// you are trying to find ANY Ruleset that matches the selector) /// </summary> public IEnumerable <Closure> FindRulesets(Selector selector) { var matchingRuleSets = Frames .Reverse() .SelectMany(frame => frame.Find <Ruleset>(this, selector, null)) .Where(matchedClosure => { if (!Frames.Any(frame => frame.IsEqualOrClonedFrom(matchedClosure.Ruleset))) { return(true); } var mixinDef = matchedClosure.Ruleset as MixinDefinition; if (mixinDef != null) { return(mixinDef.Condition != null); } return(false); }).ToList(); if (matchingRuleSets.Any()) { return(matchingRuleSets); } if (Parent != null) { var parentRulesets = Parent.FindRulesets(selector); if (parentRulesets != null) { return(parentRulesets); } } if (ClosureEnvironment != null) { return(ClosureEnvironment.FindRulesets(selector)); } return(null); }
private void MakeAndAssignEnvironments() { VisitScopeTree(ScopeTree, scope => { // Currently all variables declared in the same scope are added // to the same closure environment var variablesInEnvironment = scope.DeclaredVariables; // Don't create empty environments if (variablesInEnvironment.Count == 0) { return; } // First walk the nested scopes to find all closures which // capture variables from this scope. They all need to capture // this environment. This includes closures which captured local // functions that capture those variables, so multiple passes may // be needed. This will also decide if the environment is a struct // or a class. bool isStruct = true; var closures = new SetWithInsertionOrder <Closure>(); bool addedItem; // This loop is O(n), where n is the length of the chain // L_1 <- L_2 <- L_3 ... // where L_1 represents a local function that directly captures the current // environment, L_2 represents a local function that directly captures L_1, // L_3 represents a local function that captures L_2, and so on. // // Each iteration of the loop runs a visitor that is proportional to the // number of closures in nested scopes, so we hope that the total number // of nested functions and function chains is small in any real-world code. do { addedItem = false; VisitClosures(scope, (closureScope, closure) => { if (!closures.Contains(closure) && (closure.CapturedVariables.Overlaps(scope.DeclaredVariables) || closure.CapturedVariables.Overlaps(closures.Select(c => c.OriginalMethodSymbol)))) { closures.Add(closure); addedItem = true; isStruct &= CanTakeRefParameters(closure.OriginalMethodSymbol); } }); } while (addedItem == true); // Next create the environment and add it to the declaration scope var env = new ClosureEnvironment(variablesInEnvironment, isStruct); scope.DeclaredEnvironments.Add(env); _topLevelMethod.TryGetThisParameter(out var thisParam); foreach (var closure in closures) { closure.CapturedEnvironments.Add(env); if (thisParam != null && env.CapturedVariables.Contains(thisParam)) { closure.CapturesThis = true; } } }); }