/// <summary> /// Get sequence object from the scope memory. /// </summary> /// <param name="scope"></param> /// <param name="qsNamespace"></param> /// <param name="sequenceName"></param> /// <returns></returns> public static QsSequence GetSequence(QsScope scope, string qsNamespace, string sequenceName) { if (string.IsNullOrEmpty(qsNamespace)) { // no namespace included then it is from the local scope. var seq = (QsSequence)QsEvaluator.GetScopeValueOrNull(scope, qsNamespace, sequenceName); return(seq); } else { QsNamespace ns = QsNamespace.GetNamespace(scope, qsNamespace); return((QsSequence)ns.GetValueOrNull(sequenceName)); } }
public static QsFunction ParseFunction(QsEvaluator qse, string functionDeclaration) { if (functionDeclaration.StartsWith("@")) { return(null); } // fast check for function as = and ) before it. int eqIdx = functionDeclaration.IndexOf('='); if (eqIdx > 0) { // check if ')' exist before the equal '=' sign. while (eqIdx > 0) { eqIdx--; if (functionDeclaration[eqIdx] == ' ') { continue; // ignore spaces. } if (functionDeclaration[eqIdx] == '\t') { continue; // ignore tabs } if (functionDeclaration[eqIdx] == ')') { goto GoParseFunction; } else { return(null); } } } else { // equal sign exist. return(null); } GoParseFunction: var functionToken = TokenizeFunction(functionDeclaration); return(ParseFunction(qse, functionDeclaration, functionToken)); }
/// <summary> /// Get the quantity from the parameter body on the form ([namespace:]variable) x:var or var /// </summary> public QsValue GetIndirectQuantity(QsScope scope) { try { var q = QsEvaluator.GetScopeQsValue(scope, NamespaceName, NamespaceVariableName); return(q); } catch (QsVariableNotFoundException e) { // add extra data to the exception about the parameter name itself. // its like accumulating information on the same exception. e.ExtraData = ParameterRawText; // and throw it again throw e; } }
/// <summary> /// Get the function that is stored in the scope. /// </summary> /// <param name="scope"></param> /// <param name="realName"></param> /// <returns></returns> public static QsFunction GetFunction(QsScope scope, string qsNamespace, string functionName) { if (string.IsNullOrEmpty(qsNamespace)) { // no namespace included then it is from the local scope. // I am adding the mathmatical functions in the root namespace // so I will test for the function namespace and QsFunction function = (QsFunction)MathNamespace.GetValueOrNull(functionName); // built int math functions will be overwrite any other functions if (function != null) { return(function); } else { function = (QsFunction)QsEvaluator.GetScopeValueOrNull(scope, qsNamespace, functionName); } return(function); } else { try { QsNamespace ns = QsNamespace.GetNamespace(scope, qsNamespace); return((QsFunction)ns.GetValue(functionName)); } catch (QsVariableNotFoundException) { return(null); } } }
/// <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 override object Run(Scope scope) { string code = string.Empty; //try { if (SourceUnit.HasPath) { if (File.Exists(SourceUnit.Path)) { code = SourceUnit.GetReader().ReadToEnd(); } else { throw new QsException("File Not Found"); } } else { code = SourceUnit.GetReader().ReadToEnd(); } } //catch(Exception xx) //{ // code = LastLine; //workaround because Host have something weird in SourceTextReader that don't work linux mono //} QsEvaluator qs = QsEvaluator.CurrentEvaluator; //qs.Scope = scope; string[] lines = code.Split(Environment.NewLine.ToCharArray()); object ret = null; foreach (string line in lines) { if (!string.IsNullOrEmpty(line)) { // test for directive like %module %unitdef gogo m/s^6 // hmmm // changed it to #module .. who cares :P :P // if (line.TrimStart().StartsWith("#module")) { // this is a directive var dir = line.TrimStart(); QsRoot.Root.LoadLibrary(dir.Substring(8).Trim()); } else if (!line.StartsWith("#")) { //I want to exclude # if it was between parentthesis. // oo(ferwe#kd adflk ) # // first pass (from left to right): find the # char which is the comment. int pc = 0; // for () bool qcOpened = false; int ix = 0; StringBuilder sb = new StringBuilder(); while (ix < line.Length) { var c = line[ix]; if (c == '(') { pc++; } if (line[ix] == '"') { if (ix > 0) { if (line[ix - 1] != '\\') // not escape charachter for qoutation mark { qcOpened = !qcOpened; } } else { qcOpened = !qcOpened; } } // is it a comment charachter. if (c == '#') { if (pc == 0 && qcOpened == false) { // found the comment // break break; } } if (c == ')') { pc--; } sb.Append(c); ix++; } string l2 = sb.ToString().Trim(); // text without comment. //check the last charachter if (l2.EndsWith(";")) { //trim the ';' and silent evaluate the expression. ret = qs.SilentEvaluate(l2.Trim(';')); } else { ret = qs.Evaluate(l2); } } } } return(ret); }
/// <summary> /// Parse the give sequence text and return <see cref="QsSequence"/> if succeeded /// otherwise return null reference. /// </summary> /// <param name="qse"></param> /// <param name="sequence">Sequence Text on the form S[i,j,k, ...]() ..> 40;50<kg>; .. </param> /// <returns></returns> public static QsSequence ParseSequence(QsEvaluator qse, string sequence) { if (sequence.IndexOf("..>") < 0) { // no forward operator if (sequence.IndexOf("<..") < 0) { // no backward operator. return(null); //fast check because sequence have } } Token t = Token.ParseText(sequence); t = t.MergeTokens <MultipleSpaceToken>(); t = t.MergeTokens <PositiveSequenceToken>(); // ..> start from 0 index to +ve t = t.MergeTokens <NegativeSequenceToken>(); // <.. start from -1 index to -ve if (t.IndexOf(typeof(PositiveSequenceToken)) > -1) { t = t.RemoveTokenUntil(typeof(MultipleSpaceToken), typeof(PositiveSequenceToken)); } else if (t.IndexOf(typeof(NegativeSequenceToken)) > -1) { t = t.RemoveTokenUntil(typeof(MultipleSpaceToken), typeof(PositiveSequenceToken)); } else { return(null); } // the sequence full declaration syntax in future should look like this // S[k=n->m, l=i->j] ..> k+l/((m-n)*(j-i)) // however I only support one index this time. t = t.MergeTokens <PointerOperatorToken>(); t = t.MergeTokens <WordToken>(); t = t.MergeTokens <NumberToken>(); t = t.MergeTokens <UnitizedNumberToken>(); t = t.MergeTokens <NamespaceToken>(); t = t.MergeTokensInGroups(new ParenthesisGroupToken(), new SquareBracketsGroupToken()); t = t.RemoveSpaceTokens(); int nsidx = 0; // surve as a base for indexing token if there is namespace it will be 1 otherwise remain 0 string declaredNamespace = string.Empty; foreach (var tok in t) { if (tok.TokenClassType == typeof(NamespaceToken)) { nsidx++; declaredNamespace += tok.TokenValue; } else { break; } } declaredNamespace = declaredNamespace.TrimEnd(':'); if (t[nsidx + 0].TokenClassType == typeof(WordToken) && (t.Count > 1 ? t[nsidx + 1].TokenClassType == typeof(SquareBracketsGroupToken) : false) // test for second tokek to be [] group ) { Type SequenceTokenType = null; int shift = 0; if ((nsidx + t.Count) > 2) { //check for sequence operator if (t[nsidx + 2].TokenClassType == typeof(PositiveSequenceToken) || t[nsidx + 2].TokenClassType == typeof(NegativeSequenceToken)) { //reaching here means the sequence doesn't have parameters only indexers. SequenceTokenType = t[nsidx + 2].TokenClassType; } else if ((nsidx + t.Count) > 4) { if (t[nsidx + 3].TokenClassType == typeof(PositiveSequenceToken) || t[nsidx + 3].TokenClassType == typeof(NegativeSequenceToken)) { //reaching here means the sequence has parameterized arguments. SequenceTokenType = t[nsidx + 3].TokenClassType; //shift = nsidx + 1; shift = 1; } else { return(null); } } else { return(null); } } else { return(null); } // s[] found string sequenceName = t[nsidx + 0].TokenValue; // Specify the index area [k=m->n, l=i->j] Token IndicesArea = t[nsidx + 1]; IndicesArea = IndicesArea.RemoveSpaceTokens().TrimStart <LeftSquareBracketToken>().TrimEnd <RightSquareBracketToken>(); List <string> indexes = new List <string>(); List <string> rangeStartNames = new List <string>(); List <string> rangeEndNames = new List <string>(); if (!string.IsNullOrEmpty(IndicesArea.TokenValue)) { // IndicesArea = IndicesArea.MergeAllBut <MergedToken>(new CommaToken()); // validate the syntax and extract the information foreach (var m in IndicesArea) { if (m.Count == 1) { indexes.Add(m[0].TokenValue); rangeStartNames.Add(string.Empty); rangeEndNames.Add(string.Empty); } else { string SyntaxErrorMessage = "Sequence syntax error in indexer declaration: Correct Declaration looks like S[k] or S[k=m->n]"; if (m.Count == 5) { if (m[0].TokenClassType == typeof(WordToken) && m[1].TokenClassType == typeof(EqualToken) && m[2].TokenClassType == typeof(WordToken) && m[3].TokenClassType == typeof(PointerOperatorToken) && m[4].TokenClassType == typeof(WordToken)) { indexes.Add(m[0].TokenValue); rangeStartNames.Add(m[2].TokenValue); rangeEndNames.Add(m[4].TokenValue); } else { throw new QsSyntaxErrorException(SyntaxErrorMessage); } } else { throw new QsSyntaxErrorException(SyntaxErrorMessage); } } } } else { rangeStartNames.Add(string.Empty); rangeEndNames.Add(string.Empty); } if (indexes.Count > 1) { throw new QsException("Sequences with more than one index are not supported now"); } // get parameters string[] parameters = {}; //array with zero count :) if (t[nsidx + 2].TokenClassType == typeof(ParenthesisGroupToken)) { parameters = (from c in t[nsidx + 2] where c.TokenClassType == typeof(WordToken) select c.TokenValue).ToArray(); } //make all things between ';' be a whole word. t = t.MergeAllBut(nsidx + 3 + shift, typeof(SequenceElementToken), new SemiColonToken()); QsSequence seqo = GetSequence(qse.Scope, declaredNamespace, FormSequenceSymbolicName(sequenceName, indexes.Count, parameters.Length)); if (seqo == null) { if (SequenceTokenType == typeof(NegativeSequenceToken)) { throw new QsException("You can't initialize negative sequence elements without inititialize positive sequence element(s) first"); } seqo = new QsSequence(indexes.Count > 0 ? indexes[0] : string.Empty, parameters) { SequenceSymbolicName = sequenceName, SequenceDeclaration = t[nsidx + 0].TokenValue + t[nsidx + 1].TokenValue + t[nsidx + shift + 1].TokenValue, //(shift == nsidx + 1 ? t[nsidx + 2].TokenValue : ""), SequenceNamespace = declaredNamespace, SequenceRangeStartName = rangeStartNames[0], SequenceRangeEndName = rangeEndNames[0] }; } else { //sequence exist if (SequenceTokenType == typeof(PositiveSequenceToken)) { //it meanse I am defining the sequence again and overwrite the previous one seqo = new QsSequence(indexes.Count > 0 ? indexes[0] : string.Empty, parameters) { SequenceSymbolicName = sequenceName, SequenceDeclaration = t[nsidx + 0].TokenValue + t[nsidx + 1].TokenValue + (shift == nsidx + 1 ? t[nsidx + 2].TokenValue : ""), SequenceRangeStartName = rangeStartNames[0], SequenceRangeEndName = rangeEndNames[0] }; } else { seqo.CachedValues.Clear(); //clear all cache because we are defining extra elements. } } //beginElement is zero index element in positive sequence and -1 index element in negative sequence. QsSequenceElement beginElement = QsSequenceElement.Parse(t[nsidx + 3 + shift].TokenValue, qse, seqo); if (SequenceTokenType == typeof(PositiveSequenceToken)) { seqo[0] = beginElement; } else { seqo[-1] = beginElement; } // take the right side arguments to be added into the sequence. int seqoIndex = 5 + shift; // the argument with index 1 int ix = 1; //index of sequence. if (SequenceTokenType == typeof(NegativeSequenceToken)) { ix = -2; } while ((nsidx + seqoIndex) < t.Count) { if (t[nsidx + seqoIndex].TokenClassType != typeof(SemiColonToken)) { //assuming for now all entered values are quantities. QsSequenceElement seqoElement = QsSequenceElement.Parse(t[nsidx + seqoIndex].TokenValue, qse, seqo); seqo[ix] = seqoElement; //-5 bacause I am starting from 1 index if (SequenceTokenType == typeof(NegativeSequenceToken)) { ix--; } else { ix++; } } seqoIndex++; } return(seqo); } else { return(null); } }
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); } }