/// <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 void Validate(VisualProgram context) { if (string.IsNullOrWhiteSpace(Name)) { throw new Exception(); // TODO: Add meaningful error message. If this is thrown, variable isn't provided } if (!context.Variables.TryGetVariable(Name, out var def)) { throw new Exception(); // TODO: Add meaninful error message. If this is thrown, could not find a variable with the target name. } if (def.Type != Type) { throw new Exception(); // TODO: Add meaningful message. If this is thrown, variable is wrong type } }
/// <summary>Gets the Linq Expression for this node.</summary> /// <param name="context">The program context. Required for variables, resolving links, etc.</param> public abstract Expression CreateExpression(VisualProgram context);
public Expression ResolveRequiredExpression(VisualProgram context) => ResolveExpression(context) ?? throw new Exception();
public Expression?ResolveExpression(VisualProgram context) => isValue ? Expression.Constant(value, typeof(TValue)) : nodeId.HasValue ? context.Nodes[nodeId.Value]?.CreateExpression(context) : null;
public VisualNode ResolveRequiredNode(VisualProgram context) => ResolveNode(context) ?? throw new Exception();
#pragma warning restore CS8653 public VisualNode?ResolveNode(VisualProgram context) => isValue || !nodeId.HasValue ? null : context.Nodes[nodeId.Value];
/// <summary>Alias for <see cref="CreateLambda(VisualProgram)"/>.</summary> public override Expression CreateExpression(VisualProgram context) => CreateLambda(context);
public Expression?ResolveSetterExpression(VisualProgram context, Expression value) { try { return(ResolveRequiredSetterExpression(context, value)); } catch { return(null); } }
public Expression ResolveRequiredSetterExpression(VisualProgram context, Expression value) => VariableAccessorFactory.CreateSetterExpression(context, this, value);
public Expression?ResolveGetterExpression(VisualProgram context) { try { return(ResolveRequiredGetterExpression(context)); } catch { return(null); } }
public Expression ResolveRequiredGetterExpression(VisualProgram context) => VariableAccessorFactory.CreateGetterExpression(context, this, typeof(TVar));
/// <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));
public Expression?ResolveExpression(VisualProgram context) => ResolveNode(context)?.CreateExpression(context);
public VisualNode?ResolveNode(VisualProgram context) => context.Nodes[nodeId];