public Term PerformOperation(Executer exec, Operator op, Term otherTerm) { //these should be in Types.Object really... Types.Object oThis = null; //TODO: if it's already been evaluated this time, no need to do it again! if (this.Expression!=null) this.Value = this.Expression.Evaluate(exec); oThis = this.Value; Types.Object oOther = null; if (otherTerm!=null) { //TODO: if it's already been evaluated this time, no need to do it again! if (otherTerm.Expression!=null) otherTerm.Value = otherTerm.Expression.Evaluate(exec); oOther = otherTerm.Value; } //Here's the bad one: can't well set Value - what about next execution?? E.g. if it was a Variable?? //this.Value = oThis.PerformOperation(exec, op, oOther); //return this.Value; Term tNew = new Term(); tNew.Value = oThis.PerformOperation(exec, op, oOther); return tNew; }
private Term AddTerm(string sTerm) { if (sTerm.Length == 0) return null; Term term = new Term(sTerm); AddChunk(term); return term; }
private Term AddTerm(Expression expr) { Term term = new Term(expr); AddChunk(term); return term; }
/// <summary> /// Parse partial expression. Returns the remainder of the string (that wasn't part of the expression) /// </summary> /// <param name="sLine"></param> /// <returns></returns> public string Parse(string sLine) { //this should probably be done with regular expressions. //http://www.ultrapico.com/ExpressoDownload.htm m_aChunks = new ArrayList(); //int nChunkStart = -1; int nCharIndex = 0; while (sLine.Length>0) { string sChar = sLine.Substring(nCharIndex,1); //check for quotes: if (sChar == "\"") { int nQuoteEnd = sLine.IndexOf("\"", nCharIndex+1); //note: sQuote includes quotation marks sLine = ExtractTerm(nQuoteEnd, sLine); nCharIndex = 0; } else if (sChar == " ") { sLine = sLine.Remove(nCharIndex,1); nCharIndex = 0; } else if (sChar == ",") { //TODO: check: this can only happen to separate function arguments //end of this argument. sLine = ExtractTerm(nCharIndex-1, sLine); return sLine; //NO: .Remove(0,1); //remove the , before returning } else { //is it an operator? // if (sChar == ".") // { // EH.Put("!"); // } Operator op = Parser.GetOperator(sChar); if (op!=null) { //first check if it's a "." - it could be a decimal dot, not an operator: try { Term termTest = new Term(sLine.Substring(0,nCharIndex)); Types.Number number = (Types.Number)termTest.Value; nCharIndex++; continue; } catch {} if (nCharIndex-1 >= 0) sLine = ExtractTerm(nCharIndex-1, sLine); //could be a two-token operator. Check that too: string sChars = sLine.Substring(0,2); Operator op2 = Parser.GetOperator(sChars); if (op2!=null) { op = op2; sLine = sLine.Remove(0,2); } else sLine = sLine.Remove(0,1); //if there either is no previous chunk, or it was an operator, //that means this must be a pre-op (-a, ++a, etc) if (this.m_aChunks.Count == 0 || this.GetLastChunk().GetType() == typeof(Operator)) { op = Parser.GetOperator("pre"+op.InternalTokens); if (op == null || !op.IsPreOp) throw new Exception("Two operators in a row"); //Two operators can be joined if //current op is a pre-op and last op was NOT (a=++b or a=-b) //TODO: if (!((Operator)lastChunk).CanBePreOp) } //TODO: consider a = b+++++c (in C# it must be written b++ + ++c) // object lastChunk = this.GetLastChunk(); AddOperator(op); nCharIndex = 0; if(op.IsSettingOperator && (op.InternalTokens.IndexOf("=")>0)) { //if an operator with "=" in it, everything on right side must be calculated first. //easiest way to accomplish this is to make one single term of it. Expression expression = new Expression(); sLine = expression.Parse(sLine); Term term = this.AddTerm(expression); } } else if (Parser.m_aSeparators.IndexOf(sChar) >= 0 || nCharIndex == sLine.Length-1) { if (Parser.m_aSeparators.IndexOf(sChar) >= 0) { if (nCharIndex > 0) { sLine = ExtractTerm(nCharIndex-1, sLine); nCharIndex = 0; } } else //if (nCharIndex == sLine.Length-1) { sLine = ExtractTerm(nCharIndex, sLine); nCharIndex = 0; } bool bLastChunkWasTerm = false; object oLastChunk = null; if (this.m_aChunks.Count > 0) { oLastChunk = this.GetLastChunk(); bLastChunkWasTerm = (oLastChunk.GetType() == typeof(Term)); } if (sChar == ")" || sChar == "]" || nCharIndex == sLine.Length-1) { //we can't remove the final token - if we're parsing function arguments, //the caller must know that the end of the function has been reached. return sLine; //sLine.Remove(0,nCharIndex+1); } else if (sChar == "(" || sChar == "[") { if (sChar == "[") { //if this comes after another operator or as the first chunk in an expression, //then consider it a LingoList definition and parse it as such //otherwise, it's an index access function. //TODO: Convert this into an access function, ie object[x+1] -> object.IndexerAccess(x+1) } bool bIsFunction = false; if (sChar == "(" && bLastChunkWasTerm == true && ((Term)oLastChunk).CanBeMethod()) //.Value.GetType() == typeof(string)) bIsFunction = true; if (bIsFunction) { //the term must be marked as a function... ((Term)oLastChunk).ConvertToMethod(); // ((Term)oLastChunk).IsFunction = true; Types.Method func = (Types.Method)((Term)oLastChunk).Value; // sub.m_aChunks = new ArrayList(); //NO!! changed this: //if it's a function, it may have several arguments //We'll express this as: //term.Value = function name //term.Expression = an expression with N terms (each argument is a term) while (true) { Expression arg = new Expression(); sLine = arg.Parse(sLine.Remove(0,1)); //remove the , or ( first. // Term term = new Term(arg); // sub.m_aChunks.Add(term); if (arg.m_aChunks.Count > 0) func.AddArgument(arg); if (sLine.Length == 0 || sLine.Substring(0,1) == ")") break; } } else if (!bLastChunkWasTerm) //last term was an operator, //which means this is just a parenthesized expression (not a function) { Expression sub = new Expression(); sLine = sub.Parse(sLine.Remove(0,1)); //remove the ( this.AddTerm(sub); } else //throw exception? { } if (sLine.Length > 0 && sLine.Substring(0,1) == ")") sLine = sLine.Remove(0,1); nCharIndex = 0; } else { } } else { nCharIndex++; } } } this.ArrangeOpsInExecutionOrder(); return sLine; }