internal static IVariable[] GetCapturedLoopVariables(IEmitter emitter, AstNode context, IEnumerable <ParameterDeclaration> parameters, bool excludeReadOnly = false) { var loop = LambdaBlock.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 VisitLambdaExpression(LambdaExpression lambdaExpression) { if (captureOnly) { var analyzer = new CaptureAnalyzer(this.emitter); analyzer.Analyze(lambdaExpression.Body, lambdaExpression.Parameters.Select(p => p.Name)); if (analyzer.UsedVariables.Count > 0) { this.LambdaExpression.Add(lambdaExpression); } } else { this.LambdaExpression.Add(lambdaExpression); } base.VisitLambdaExpression(lambdaExpression); }
public override void VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression) { if (captureOnly) { var analyzer = new CaptureAnalyzer(this.emitter.Resolver.Resolver); analyzer.Analyze(anonymousMethodExpression.Body, anonymousMethodExpression.Parameters.Select(p => p.Name)); if (analyzer.UsedVariables.Count > 0) { this.LambdaExpression.Add(anonymousMethodExpression); } } else { this.LambdaExpression.Add(anonymousMethodExpression); } base.VisitAnonymousMethodExpression(anonymousMethodExpression); }
public override void VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression) { var analyzer = new CaptureAnalyzer(this.resolver); 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) { this._usesThis = true; } //base.VisitAnonymousMethodExpression(anonymousMethodExpression); }
public override void VisitLambdaExpression(LambdaExpression lambdaExpression) { var analyzer = new CaptureAnalyzer(this.emitter); analyzer.Analyze(lambdaExpression.Body, lambdaExpression.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) { this._usesThis = true; } //base.VisitLambdaExpression(lambdaExpression); }
private string[] GetCapturedLoopVariables() { var loop = this.GetOuterLoop(); if (loop == null) { return(null); } var loopVariablesAnalyzer = new LoopVariablesAnalyzer(this.Emitter); loopVariablesAnalyzer.Analyze(loop); var captureAnalyzer = new CaptureAnalyzer(this.Emitter); captureAnalyzer.Analyze(this.Context, this.Parameters.Select(p => p.Name)); var capturedVariables = captureAnalyzer.UsedVariables.Where(v => loopVariablesAnalyzer.Variables.Contains(v)).ToArray(); List <string> names = new List <string>(); foreach (var capturedVariable in capturedVariables) { if (this.Emitter.LocalsMap != null && this.Emitter.LocalsMap.ContainsKey(capturedVariable)) { names.Add(this.Emitter.LocalsMap[capturedVariable]); } else if (this.Emitter.LocalsNamesMap != null && this.Emitter.LocalsNamesMap.ContainsKey(capturedVariable.Name)) { names.Add(this.Emitter.LocalsNamesMap[capturedVariable.Name]); } else { names.Add(capturedVariable.Name); } } return(names.ToArray()); }
protected virtual void EmitLambda(IEnumerable <ParameterDeclaration> parameters, AstNode body, AstNode context) { var analyzer = new CaptureAnalyzer(this.Emitter.Resolver.Resolver); analyzer.Analyze(this.Body, this.Parameters.Select(p => p.Name)); var oldLevel = this.Emitter.Level; if (analyzer.UsedVariables.Count == 0) { this.Emitter.Level = 1; } AsyncBlock asyncBlock = null; this.PushLocals(); if (this.IsAsync) { if (context is LambdaExpression) { asyncBlock = new AsyncBlock(this.Emitter, (LambdaExpression)context); } else { asyncBlock = new AsyncBlock(this.Emitter, (AnonymousMethodExpression)context); } asyncBlock.InitAsyncBlock(); } var prevMap = this.BuildLocalsMap(); var prevNamesMap = this.BuildLocalsNamesMap(); this.AddLocals(parameters, body); bool block = body is BlockStatement; this.Write(""); var savedPos = this.Emitter.Output.Length; var savedThisCount = this.Emitter.ThisRefCounter; this.WriteFunction(); this.EmitMethodParameters(parameters, null, context); this.WriteSpace(); int pos = 0; if (!block && !this.IsAsync) { this.BeginBlock(); pos = this.Emitter.Output.Length; } bool isSimpleLambda = body.Parent is LambdaExpression && !block && !this.IsAsync; if (isSimpleLambda) { this.ConvertParamsToReferences(parameters); var rr = this.Emitter.Resolver.ResolveNode(this.Context, this.Emitter) as LambdaResolveResult; if (rr == null || rr.ReturnType.Kind != TypeKind.Void) { this.WriteReturn(true); } } if (this.IsAsync) { asyncBlock.Emit(true); } else { body.AcceptVisitor(this.Emitter); } if (isSimpleLambda) { this.WriteSemiColon(); } if (!block && !this.IsAsync) { this.WriteNewLine(); this.EndBlock(); } if (!block && !this.IsAsync) { this.EmitTempVars(pos); } if (analyzer.UsedVariables.Count == 0) { var name = "f" + (this.Emitter.NamedFunctions.Count + 1); var code = this.Emitter.Output.ToString().Substring(savedPos); var pair = this.Emitter.NamedFunctions.FirstOrDefault(p => p.Value == code); if (pair.Key != null && pair.Value != null) { name = pair.Key; } else { this.Emitter.NamedFunctions.Add(name, code); } this.Emitter.Output.Remove(savedPos, this.Emitter.Output.Length - savedPos); this.Emitter.Output.Insert(savedPos, "$_." + BridgeTypes.ToJsName(this.Emitter.TypeInfo.Type, this.Emitter, true) + "." + name); this.Emitter.Level = oldLevel; } if (this.Emitter.ThisRefCounter > savedThisCount) { this.Emitter.Output.Insert(savedPos, Bridge.Translator.Emitter.ROOT + "." + Bridge.Translator.Emitter.DELEGATE_BIND + "(this, "); this.WriteCloseParentheses(); } this.PopLocals(); this.ClearLocalsMap(prevMap); this.ClearLocalsNamesMap(prevNamesMap); }
protected virtual void EmitLambda(IEnumerable <ParameterDeclaration> parameters, AstNode body, AstNode context) { var rr = this.Emitter.Resolver.ResolveNode(context, this.Emitter); var oldLifting = this.Emitter.ForbidLifting; this.Emitter.ForbidLifting = false; var analyzer = new CaptureAnalyzer(this.Emitter); analyzer.Analyze(this.Body, this.Parameters.Select(p => p.Name)); var oldLevel = this.Emitter.Level; if (analyzer.UsedVariables.Count == 0) { this.Emitter.ResetLevel(); Indent(); } AsyncBlock asyncBlock = null; this.PushLocals(); if (this.IsAsync) { if (context is LambdaExpression) { asyncBlock = new AsyncBlock(this.Emitter, (LambdaExpression)context); } else { asyncBlock = new AsyncBlock(this.Emitter, (AnonymousMethodExpression)context); } asyncBlock.InitAsyncBlock(); } var prevMap = this.BuildLocalsMap(); var prevNamesMap = this.BuildLocalsNamesMap(); this.AddLocals(parameters, body); bool block = body is BlockStatement; this.Write(""); var savedPos = this.Emitter.Output.Length; var savedThisCount = this.Emitter.ThisRefCounter; var capturedVariables = this.GetCapturedLoopVariables(); if (capturedVariables != null && capturedVariables.Length > 0) { this.Write("(function (" + string.Join(", ", capturedVariables) + ") "); this.BeginBlock(); this.Write("return "); } this.WriteFunction(); this.EmitMethodParameters(parameters, null, context); this.WriteSpace(); int pos = 0; if (!block && !this.IsAsync) { this.BeginBlock(); pos = this.Emitter.Output.Length; } bool isSimpleLambda = body.Parent is LambdaExpression && !block && !this.IsAsync; if (isSimpleLambda) { this.ConvertParamsToReferences(parameters); var lrr = rr as LambdaResolveResult; if (lrr == null || lrr.ReturnType.Kind != TypeKind.Void) { this.WriteReturn(true); } } if (this.IsAsync) { asyncBlock.Emit(true); } else { body.AcceptVisitor(this.Emitter); } if (isSimpleLambda) { this.WriteSemiColon(); } if (!block && !this.IsAsync) { this.WriteNewLine(); this.EndBlock(); } if (!block && !this.IsAsync) { this.EmitTempVars(pos); } if (analyzer.UsedVariables.Count == 0) { if (!this.Emitter.ForbidLifting) { var name = "f" + (this.Emitter.NamedFunctions.Count + 1); var code = this.Emitter.Output.ToString().Substring(savedPos); var pair = this.Emitter.NamedFunctions.FirstOrDefault(p => p.Value == code); if (pair.Key != null && pair.Value != null) { name = pair.Key; } else { this.Emitter.NamedFunctions.Add(name, code); } this.Emitter.Output.Remove(savedPos, this.Emitter.Output.Length - savedPos); this.Emitter.Output.Insert(savedPos, JS.Vars.D_ + "." + BridgeTypes.ToJsName(this.Emitter.TypeInfo.Type, this.Emitter, true) + "." + name); } this.Emitter.ResetLevel(oldLevel); } this.Emitter.ForbidLifting = oldLifting; var methodDeclaration = this.Body.GetParent <MethodDeclaration>(); if (this.Emitter.ThisRefCounter > savedThisCount || this.IsAsync && methodDeclaration != null && !methodDeclaration.HasModifier(Modifiers.Static)) { this.Emitter.Output.Insert(savedPos, JS.Funcs.BRIDGE_BIND + "(this, "); this.WriteCloseParentheses(); } if (capturedVariables != null && capturedVariables.Length > 0) { this.WriteSemiColon(true); this.EndBlock(); this.Write(")(" + string.Join(", ", capturedVariables) + ")"); } this.PopLocals(); this.ClearLocalsMap(prevMap); this.ClearLocalsNamesMap(prevNamesMap); }