/// <summary> /// Creates element from sequence. /// The element will return the target sequence with the same index. /// </summary> /// <param name="sequence"></param> /// <returns></returns> public static QsSequenceElement FromSequenceAccess(QsSequence sequence) { QsSequenceElement el = new QsSequenceElement(); el.ElementValue = sequence; el.IndexEvaluation = false; el.ParameterEvaluation = false; return(el); }
/// <summary> /// Execute the element by accepting the index of execution. /// index of execution may differ on IndexInParentSequence. /// </summary> /// <param name="executionIndex">The real calling index.</param> /// <returns></returns> public QsValue Execute(int executionIndex) { if (ElementValue.GetType() == typeof(Func <int, QsValue>)) { return(((Func <int, QsValue>)ElementValue)(executionIndex)); } else if (ElementValue.GetType() == typeof(QsSequence)) { QsSequence seq = (QsSequence)ElementValue; return((QsValue)seq.GetElementValue(executionIndex)); } else { return((QsValue)ElementValue); } }
/// <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 :( :( :( "); }
/// <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); } }