/// <summary> /// Creates the lambda expression from the statements attached to this entry and the parameter definitions in the provided program context. /// </summary> public LambdaExpression CreateLambda(VisualProgram context) { if (!context.Environment.EntryDefinitions.TryGetValue(VisualEntryId, out var def)) { throw new KeyNotFoundException($"Could not find an entry with ID '{VisualEntryId}' in the VisualProgram's entry definitions."); } // Create a parameter for each expected/defined parameter var parameters = def.Parameters.Map(Expression.Parameter); return(Expression.Lambda( Expression.Block( // Before doing the main body of the entry function, make expressions to copy the incoming parameters to variables ParameterMap .Where(mapping => !string.IsNullOrWhiteSpace(mapping.Value)) // Exclude any that don't actually map to anything .Select(p => VariableAccessorFactory.CreateSetterExpression( context, VariableReference.Create(def.Parameters[p.Key], p.Value), parameters[p.Key] ) ).Concat( // Then do the actual main body NodeUtils.FlattenExpressions(context, FirstStatement) ) ), // All lambdas will get a context parameter // We also pass the defined parameters to the lambda so it knows what types to expect and what signature to have. // This needs to happen regardless or not of whether the parameters are actually used by the entry function as this determines the delegate's signature. new[] { context.Variables.compiledInstanceParameter }.Concat(parameters) )); }
/// <summary>Resolves this reference into a single <see cref="BlockExpression"/> containing all the sequential statements. /// If there are no statements that would end up in the block, throws an exception.</summary> /// <exception cref="Exception"></exception> public BlockExpression ResolveRequiredStatement(VisualProgram context) { var body = NodeUtils.FlattenExpressions(context, this); if (body.Count() == 0) { throw new Exception(); // TODO Add meaningful message } return(Expression.Block(expressions: body)); }
public override Expression CreateExpression(VisualProgram context) { var branches = NodeUtils.FlattenExpressions(context, TrueBranch, FalseBranch); return(Expression.IfThenElse( Condition.ResolveRequiredExpression(context), Expression.Block(branches.branch1Flattened), Expression.Block(branches.branch2Flattened) )); }
/// <summary> /// Compiles the entries in the given Program into delegates. /// Returns the delegates themselves and the delegate signatures (excluding the context parameter). /// </summary> private FunctionStore CompileEntryDelegates(VisualProgram program) { var progEntryNodes = program.Nodes.OfType <VisualEntry>().ToDictionary(ve => ve.VisualEntryId, ve => ve); return(program.Environment.EntryDefinitions.ToDictionary( entry => entry.Key, entry => { // If the program does not contain this entry node OR it exists but is not connected to any statements, then return no delegate if (!progEntryNodes.TryGetValue(entry.Value.Id, out var startNode) || !startNode.FirstStatement.HasValue) { return null; } // Create a parameter for each expected/defined parameter var parameters = entry.Value.Parameters.Map(Expression.Parameter); // Compile and return the lambda return Expression.Lambda( Expression.Block( // Before doing the main body of the entry function, make expressions to copy the incoming parameters to variables startNode.ParameterMap .Where(mapping => !string.IsNullOrWhiteSpace(mapping.Value)) // Exclude any that don't actually map to anything .Select(p => VariableAccessorFactory.CreateSetterExpression( program, VariableReference.Create(entry.Value.Parameters[p.Key], p.Value), parameters[p.Key] ) ).Concat( // Then do the actual main body NodeUtils.FlattenExpressions(program, startNode.FirstStatement) ) ), // All lambdas will get a context parameter // We also pass the defined parameters to the lambda so it knows what types to expect and what signature to have. // This needs to happen regardless or not of whether the parameters are actually used by the entry function as this determines the delegate's signature. new[] { program.Variables.compiledInstanceParameter }.Concat(parameters) ).Compile(); }, StringComparer.OrdinalIgnoreCase )); }
/// <summary>Resolves this reference into a single <see cref="BlockExpression"/> containing all the sequential statements.</summary> public BlockExpression ResolveStatement(VisualProgram context) => Expression.Block(expressions: NodeUtils.FlattenExpressions(context, this));