internal static IVariable[] GetCapturedLoopVariables(IEmitter emitter, AstNode context, IEnumerable <ParameterDeclaration> parameters, bool excludeReadOnly = false) { var loop = GetOuterLoop(context); if (loop == null) { return(null); } var loopVariablesAnalyzer = new LoopVariablesAnalyzer(emitter, excludeReadOnly); loopVariablesAnalyzer.Analyze(loop); var captureAnalyzer = new CaptureAnalyzer(emitter); captureAnalyzer.Analyze(context, parameters.Select(p => p.Name)); return(captureAnalyzer.UsedVariables.Where(v => loopVariablesAnalyzer.Variables.Contains(v)).ToArray()); }
public override void VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression) { CheckExpression(anonymousMethodExpression); var analyzer = new CaptureAnalyzer(emitter); analyzer.Analyze(anonymousMethodExpression.Body, anonymousMethodExpression.Parameters.Select(p => p.Name)); foreach (var usedVariable in analyzer.UsedVariables) { if (!_variables.Contains(usedVariable.Name) && !_usedVariables.Contains(usedVariable)) { _usedVariables.Add(usedVariable); } } if (analyzer.UsesThis) { _usesThis = true; } //base.VisitAnonymousMethodExpression(anonymousMethodExpression); }
protected virtual void EmitLambda(IEnumerable <ParameterDeclaration> parameters, AstNode body, AstNode context) { var rr = Emitter.Resolver.ResolveNode(context); var oldLifting = Emitter.ForbidLifting; Emitter.ForbidLifting = false; var noLiftingRule = Emitter.Rules.Lambda == LambdaRule.Plain; CaptureAnalyzer analyzer = null; if (!noLiftingRule) { analyzer = new CaptureAnalyzer(Emitter); analyzer.Analyze(Body, Parameters.Select(p => p.Name)); } var oldLevel = Emitter.Level; if (!noLiftingRule && analyzer.UsedVariables.Count == 0) { Emitter.ResetLevel(); Indent(); } IAsyncBlock asyncBlock = null; PushLocals(); if (IsAsync) { if (context is LambdaExpression) { asyncBlock = new AsyncBlock(Emitter, (LambdaExpression)context); } else { asyncBlock = new AsyncBlock(Emitter, (AnonymousMethodExpression)context); } asyncBlock.InitAsyncBlock(); } else if (YieldBlock.HasYield(body)) { IsAsync = true; if (context is LambdaExpression) { asyncBlock = new GeneratorBlock(Emitter, (LambdaExpression)context); } else { asyncBlock = new GeneratorBlock(Emitter, (AnonymousMethodExpression)context); } asyncBlock.InitAsyncBlock(); } var prevMap = BuildLocalsMap(); var prevNamesMap = BuildLocalsNamesMap(); AddLocals(parameters, body); bool block = body is BlockStatement; Write(""); var savedThisCount = Emitter.ThisRefCounter; var capturedVariables = GetCapturedLoopVariablesNames(); var hasCapturedVariables = capturedVariables != null && capturedVariables.Length > 0; if (hasCapturedVariables) { Write("(function ($me, "); Write(string.Join(", ", capturedVariables) + ") "); BeginBlock(); Write("return "); } var savedPos = Emitter.Output.Length; WriteFunction(); EmitMethodParameters(parameters, null, context); WriteSpace(); int pos = 0; if (!block && !IsAsync) { BeginBlock(); pos = Emitter.Output.Length; } bool isSimpleLambda = body.Parent is LambdaExpression && !block && !IsAsync; if (isSimpleLambda) { ConvertParamsToReferences(parameters); if (!(rr is LambdaResolveResult lrr) || lrr.ReturnType.Kind != TypeKind.Void) { WriteReturn(true); } } if (IsAsync) { asyncBlock.Emit(true); } else { body.AcceptVisitor(Emitter); } if (isSimpleLambda) { WriteSemiColon(); } if (!block && !IsAsync) { WriteNewLine(); EndBlock(); } if (!block && !IsAsync) { EmitTempVars(pos); } if (!noLiftingRule && analyzer.UsedVariables.Count == 0) { if (!Emitter.ForbidLifting) { var name = "f" + (Emitter.NamedFunctions.Count + 1); var code = Emitter.Output.ToString().Substring(savedPos); var codeForComare = RemoveTokens(code); var pair = Emitter.NamedFunctions.FirstOrDefault(p => { if (Emitter.AssemblyInfo.SourceMap.Enabled) { return(RemoveTokens(p.Value) == codeForComare); } return(p.Value == code); }); if (pair.Key != null && pair.Value != null) { name = pair.Key; } else { Emitter.NamedFunctions.Add(name, code); } Emitter.Output.Remove(savedPos, Emitter.Output.Length - savedPos); Emitter.Output.Insert(savedPos, JS.Vars.D_ + "." + H5Types.ToJsName(Emitter.TypeInfo.Type, Emitter, true) + "." + name); } Emitter.ResetLevel(oldLevel); } Emitter.ForbidLifting = oldLifting; var methodDeclaration = Body.GetParent <MethodDeclaration>(); var thisCaptured = Emitter.ThisRefCounter > savedThisCount || IsAsync && methodDeclaration != null && !methodDeclaration.HasModifier(Modifiers.Static); if (thisCaptured) { Emitter.Output.Insert(savedPos, JS.Funcs.H5_BIND + (hasCapturedVariables ? "($me, " : "(this, ")); WriteCloseParentheses(); } if (hasCapturedVariables) { WriteSemiColon(true); EndBlock(); Write(")("); Write("this, "); Write(string.Join(", ", capturedVariables)); Write(")"); } PopLocals(); ClearLocalsMap(prevMap); ClearLocalsNamesMap(prevNamesMap); }