/// <summary> /// Differentiate operation for function. /// </summary> /// <param name="value">object of <see cref="QsScalar"/> that hold <see cref="AnyQuantity<SymbolicVariable>"/></param> /// <returns></returns> public override QsValue DifferentiateOperation(QsValue value) { QsScalar sval = (QsScalar)value; if (sval.ScalarType == ScalarTypes.SymbolicQuantity) { var dsv = sval.SymbolicQuantity.Value; string fname = "_"; string WholeFunction = string.Empty; if (this.FunctionBodyToken[0].TokenClassType == typeof(CurlyBracketGroupToken)) { // vector differentiation // take every term in the vector and differentiate it var vcs = QsVar.VectorComponents(this.FunctionBodyToken[0]); StringBuilder sc = new StringBuilder(); sc.Append(fname + "(" + RemoveRedundantParameters(this.ParametersNames) + ") = "); sc.Append("{ "); foreach (var c in vcs) { SymbolicVariable nsv = SymbolicVariable.Parse(c); int times = (int)dsv.SymbolPower; while (times > 0) { nsv = nsv.Differentiate(dsv.Symbol); times--; } sc.Append(nsv.ToString()); sc.Append(" "); } sc.Append("}"); WholeFunction = sc.ToString(); } else { SymbolicVariable nsv = ToSymbolicVariable(); int times = (int)dsv.SymbolPower; while (times > 0) { nsv = nsv.Differentiate(dsv.Symbol); times--; } WholeFunction = fname + "(" + RemoveRedundantParameters(this.ParametersNames) + ") = " + nsv.ToString(); } return(QsFunction.ParseFunction(QsEvaluator.CurrentEvaluator, WholeFunction)); } else { return(base.DifferentiateOperation(value)); } }
/// <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); } }
/// <summary> /// Evaluate every argument and call the suitable function /// </summary> /// <param name="vario"></param> /// <returns></returns> internal Expression GetInvokeExpression(QsVar vario, string[] args) { List <Expression> parameters = new List <Expression>(); for (int ip = 0; ip < args.Count(); ip++) { Expression nakedParameter; Expression rawParameter = Expression.Constant(args[ip].Trim()); if (this.Parameters[ip].Type == QsParamType.Function) //is this parameter in declaration is pointing to function handle { //yes: treat this parameter as function handle // get the argument as a string value to be used after that as a function name. nakedParameter = Expression.Constant(args[ip]); // and I will postpone the evaluation until we process the function. //expression to make parameter from the corresponding naked parameter parameters.Add(Expression.Call(typeof(QsParameter).GetMethod("MakeParameter"), nakedParameter, rawParameter)); } else if (this.Parameters[ip].Type == QsParamType.Raw) { //don't evaluate the parameter // just take the text and pass it to the function as it is. nakedParameter = Expression.Constant(QsParameter.MakeParameter(args[ip], args[ip])); parameters.Add(nakedParameter); } else { //normal variable nakedParameter = vario.ParseArithmatic(args[ip]); // if this was another function name without like v(c,g,8) where g is a function name will be passed to c // then excpetion will occur in GetQuantity that variable was not found in the scope Expression tryBody = Expression.Call(typeof(QsParameter).GetMethod("MakeParameter"), nakedParameter, rawParameter); // -> Catch(QsVariableNotFoundException e) {QsParameter.MakeParameter(e.ExtraData, args[ip])} var e = Expression.Parameter(typeof(QsVariableNotFoundException), "e"); Expression catchBody = Expression.Call(typeof(QsParameter).GetMethod("MakeParameter"), Expression.Property(e, "ExtraData"), rawParameter); // The try catch block when catch exception will execute the call but by passing the parameter as text only /* * var tt = Utils.Try(tryBody); * * tt.Catch(e, catchBody); * Expression tryc = tt.ToExpression() */ Expression tryc = Expression.TryCatch(tryBody, Expression.Catch(e, catchBody)); parameters.Add(tryc); } } var qsParamArray = Expression.NewArrayInit(typeof(QsParameter), parameters); return(Expression.Call(Expression.Constant(this), this.GetType().GetMethod("InvokeByQsParameters"), qsParamArray)); }