private Expression BuildFunCallExpressionFromMethodInfo(AtomMetadata atom, ParseTreeNode root, CompilerState state) { // number of arguments must exactly match number of child nodes in the tree var paramInfo = atom.MethodInfo.GetParameters(); var funArgs = root.RequireChild("exprList", 1, 0); funArgs.RequireChildren(paramInfo.Length); // types and order of arguments must match nodes in the tree var args = new Expression[paramInfo.Length]; for (var i = 0; i < paramInfo.Length; i++) { var param = paramInfo[i]; var argNode = funArgs.ChildNodes[i]; var value = state.ParentRuntime.Analyze(argNode, state); Expression adjusted; if (!ExpressionTreeExtensions.TryAdjustReturnType(root, value, param.ParameterType, out adjusted)) { throw new CompilationException(string.Format("Could not adjust parameter number {0} to invoke function {1}", i, atom.Name), funArgs.ChildNodes[i]); } args[i] = adjusted; } return(BuildFunctorInvokeExpression(atom, args)); }
private Expression BuildFunctorInvokeExpression(AtomMetadata atom, Expression adjustedContext) { if (adjustedContext == null) { return(atom.MethodTarget == null ? Expression.Call(atom.MethodInfo) : Expression.Call(Expression.Constant(atom.MethodTarget), atom.MethodInfo)); } return(atom.MethodTarget == null ? Expression.Call(atom.MethodInfo, adjustedContext) : Expression.Call(Expression.Constant(atom.MethodTarget), atom.MethodInfo, adjustedContext)); }
/// <summary> /// Registers a new atom. This API is for statically known identifiers and functions. /// To process identifiers whose names are not known at the time of runtime init use /// <see cref="IExpressionEvaluatorRuntime.RegisterDynamicAtomHandler"/>. /// </summary> /// <param name="atom">An atom to register</param> /// <seealso cref="AtomMetadata"/> /// <seealso cref="IExpressionEvaluatorRuntime.RegisterDynamicAtomHandler"/> public void RegisterAtom(AtomMetadata atom) { if (atom == null) { throw new ArgumentNullException("atom"); } if (atom.AtomType != AtomType.Function && atom.AtomType != AtomType.Identifier) { throw new ArgumentException("Atom type is invalid: " + atom.AtomType); } if (!m_atoms.TryAdd(atom.Name, atom)) { throw new ArgumentException("Atom with the same name is already registered: " + atom.Name); } }
/// <summary> /// Registers an atom to process identifiers whose names are not known at the time of runtime initialization. /// Atom will be used as a handler and must have non-null <see cref="AtomMetadata.ExpressionGenerator"/> member. /// This handler will be invoked from inside <see cref="IExpressionEvaluatorRuntime.Analyze"/> for identifiers which are not statically known atoms. /// More than one handler can be registered, they will be invoked one after another in arbitrary order /// until one of their expression generators returns a non-null value. /// </summary> /// <param name="atom">An atom to register. Must have non-null value of <see cref="AtomMetadata.ExpressionGenerator"/></param> /// <see cref="IExpressionEvaluatorRuntime.RegisterAtom"/> /// <see cref="AtomMetadata.ExpressionGenerator"/> public void RegisterDynamicAtomHandler(AtomMetadata atom) { if (atom == null) { throw new ArgumentNullException("atom"); } if (atom.AtomType != AtomType.Function && atom.AtomType != AtomType.Identifier) { throw new ArgumentException("Atom type is invalid: " + atom.AtomType); } if (atom.ExpressionGenerator == null) { throw new ArgumentException("Atom handlers must have non-null ExpressionGenerator member", "atom"); } m_atomHandlers.Add(atom); }
private Expression BuildFunctorInvokeExpression(AtomMetadata atom, Expression[] args) { return(atom.MethodTarget == null ? Expression.Call(atom.MethodInfo, args) : Expression.Call(Expression.Constant(atom.MethodTarget), atom.MethodInfo, args)); }