/// <summary> /// Returns a delegate to native c# function. /// </summary> /// <param name="method"></param> internal static System.Delegate FormNativeFunctionDelegate(MethodInfo method) { bool DecorateNativeFunction = false; if (method.ReturnType != typeof(QsValue)) { DecorateNativeFunction = true; } //construct the lambda SimpleLambdaBuilder lb = SimpleLambdaBuilder.Create(typeof(QsValue), method.Name); //prepare parameters with the same name of native function but with qsparameter type var parameters = method.GetParameters(); foreach (var prm in parameters) { if (prm.ParameterType != typeof(QsParameter)) { DecorateNativeFunction = true; } lb.Parameter(typeof(QsParameter), prm.Name); } if (!DecorateNativeFunction) { #region Delegate creation section switch (parameters.Length) { case 0: return(System.Delegate.CreateDelegate( typeof(Func <QsValue>), method)); case 1: return(System.Delegate.CreateDelegate( typeof(Func <QsParameter, QsValue>), method)); case 2: return(System.Delegate.CreateDelegate( typeof(Func <QsParameter, QsParameter, QsValue>), method)); case 3: return(System.Delegate.CreateDelegate( typeof(Func <QsParameter, QsParameter, QsParameter, QsValue>), method)); case 4: return(System.Delegate.CreateDelegate( typeof(Func <QsParameter, QsParameter, QsParameter, QsParameter, QsValue>), method)); case 5: return(System.Delegate.CreateDelegate( typeof(Func <QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsValue>), method)); case 6: return(System.Delegate.CreateDelegate( typeof(Func <QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsValue>), method)); case 7: return(System.Delegate.CreateDelegate( typeof(Func <QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsValue>), method)); case 8: return(System.Delegate.CreateDelegate( typeof(Func <QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsValue>), method)); case 9: return(System.Delegate.CreateDelegate( typeof(Func <QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsValue>), method)); case 10: return(System.Delegate.CreateDelegate( typeof(Func <QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsValue>), method)); case 11: return(System.Delegate.CreateDelegate( typeof(Func <QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsValue>), method)); case 12: return(System.Delegate.CreateDelegate( typeof(Func <QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsParameter, QsValue>), method)); } #endregion } // we will form a function body that // 1- check the parameter // 2- convert the parameter into native c# during runtime so it can be passed to the desired function List <Expression> statements = new List <Expression>(); var qns = typeof(QsNamespace); var qsys = typeof(Root); var convparMethod = qsys.GetMethod("QsParametersToNativeValues", BindingFlags.Static | BindingFlags.Public); var NTOQ = qsys.GetMethod("NativeToQsConvert", BindingFlags.Static | BindingFlags.Public); var iv = qns.GetMethod("IndirectInvoke", BindingFlags.Static | BindingFlags.NonPublic); Expression methodExpress = Expression.Constant(method); if (parameters.Length > 0) { // Take the function parameter values // to convert it to native values if required. // convert to array of QsParameter var parms = Expression.NewArrayInit(typeof(QsParameter), lb.Parameters.ToArray()); // Convert to array of Object Expression ConvertedParametersExpression = Expression.Call(convparMethod, methodExpress, parms); var rr = Expression.Call(iv, methodExpress, ConvertedParametersExpression); var vv = Expression.Call(NTOQ, rr); statements.Add(vv); } else { var parms = Expression.NewArrayInit(typeof(object)); var rr = Expression.Call(iv, methodExpress, parms); //var rr = Expression.Call(null, method); var vv = Expression.Call(NTOQ, rr); statements.Add(vv); } lb.Body = Expression.Block(statements); LambdaExpression lbe = lb.MakeLambda(); return(lbe.Compile()); }
/// <summary> /// Parse the element text and make the element point to delegate which evaluate the text if necessary. /// </summary> /// <param name="element"></param> /// <returns></returns> public static QsSequenceElement Parse(string element, QsEvaluator qse, QsSequence sequence) { if (string.IsNullOrEmpty(element)) { throw new QsException("Can't create element from empty string."); } //try direct quantity AnyQuantity <double> v; if (Unit.TryParseQuantity(element, out v)) { var el = QsSequenceElement.FromQuantity(new QsScalar { NumericalQuantity = v }); el.ElementDeclaration = element; el.IndexEvaluation = false; el.ParameterEvaluation = false; return(el); } else { QsSequenceElement se = new QsSequenceElement(); //try one index delegate without parameters //Create the lambda function that will pass the index and parameters to the expression. SimpleLambdaBuilder lb = SimpleLambdaBuilder.Create(typeof(QsValue), "ElementValue"); //add the index parameter lb.Parameter(typeof(int), sequence.SequenceIndexName); //find the index parameter in line to know if it will be evaluated or not if (element.IndexOf(sequence.SequenceIndexName) > -1) { se.IndexEvaluation = true; } //make the sequence parameters. foreach (var seqParam in sequence.Parameters) { lb.Parameter(typeof(QsValue), seqParam.Name); if (element.IndexOf(seqParam.Name) > -1) { se.ParameterEvaluation = true; } } QsVar pvar = new QsVar(qse, element, sequence, lb); lb.Body = pvar.ResultExpression; LambdaExpression le = lb.MakeLambda(); se.ElementDeclaration = element; se.ElementExpression = pvar.ResultExpression; se.ElementValue = le.Compile(); return(se); } throw new QsException("Check me in sequence element :( :( :( "); }
public static QsFunction ParseFunction(QsEvaluator qse, string functionDeclaration, Token functionToken) { int nsidx = 0; // surve as a base for indexing token if there is namespace it will be 1 otherwise remain 0 // specify the namespaces end token. string functionNamespace = ""; foreach (var tok in functionToken) { if (tok.TokenClassType == typeof(NamespaceToken)) { nsidx++; functionNamespace += tok.TokenValue; } else { break; } } if ( functionToken[nsidx].TokenClassType == typeof(WordToken) && (functionToken.Count > (nsidx + 1) ? functionToken[nsidx + 1].TokenClassType == typeof(ParenthesisGroupToken) : false) && (functionToken.Count > (nsidx + 2) ? functionToken[nsidx + 2].TokenClassType == typeof(EqualToken) : false) ) { //get function name // will be the first token after excluding namespace. string functionName = string.Empty; functionName = functionToken[nsidx].TokenValue; //remove the last : from namespace functionNamespace = functionNamespace.TrimEnd(':'); List <string> textParams = new List <string>(); List <QsParamInfo> prms = new List <QsParamInfo>(); foreach (var c in functionToken[nsidx + 1]) { if ( c.TokenValue.StartsWith("(") || c.TokenValue.StartsWith(")") || c.TokenValue.StartsWith(",") || c.TokenClassType == typeof(MultipleSpaceToken) ) { //ignore these things. } else { if (char.IsLetter(c.TokenValue[0])) { textParams.Add(c.TokenValue); prms.Add(new QsParamInfo { Name = c.TokenValue, Type = QsParamType.Value }); } else { throw new QsSyntaxErrorException("Parameter name must statrt with a letter"); } } } //declared for first time a default function. QsFunction qf = new QsFunction(functionDeclaration) { FunctionNamespace = functionNamespace, FunctionName = functionName, Parameters = prms.ToArray() }; //LambdaBuilder lb = Utils.Lambda(typeof(QsValue), functionName); SimpleLambdaBuilder lb = SimpleLambdaBuilder.Create(typeof(QsValue), functionName); foreach (QsParamInfo prm in prms) { lb.Parameter(typeof(QsParameter), prm.Name); } List <Expression> statements = new List <Expression>(); qf.FunctionBody = functionDeclaration.Substring(functionToken[nsidx + 2].IndexInText + functionToken[nsidx + 2].TokenValueLength).Trim(); Token functionBodyTokens; QsVar qv = new QsVar(qse, qf.FunctionBody, qf, lb, out functionBodyTokens); statements.Add(qv.ResultExpression); //making the variable expression itself make it the return value of the function. lb.Body = Expression.Block(statements); LambdaExpression lbe = lb.MakeLambda(); qf.FunctionExpression = lbe; qf.FunctionBodyToken = functionBodyTokens; return(qf); } else { return(null); } }