// Read a MalSequence, checking that it starts and terminates correctly. // Named read_list to follow the ref, but has been genericized to handle vectors as well. static public MalSeq read_list(Reader reader, MalSeq sequence, char start, char end) { // Check that we are in fact at the start of a list. string token = reader.Next(); if (token[0] != start) { // Parse error - probably internal if the list code is correct. throw new MalInternalError("Sequence expected '" + start + "' but got: " + token); } // Use read_form to get the list's contents, accumulating them into the list. while (true) { token = reader.Peek(); if (token != null) { // We are in the list or at the end. if (token[0] == end) { // Reached valid end of list. Consume the end char. reader.Next(); // And we are done. break; } // Mutually recurse to read the next list element. MalVal newVal = read_form(reader); sequence.Add(newVal); } else { // The input has finished but the list hasn't. Try to get more input. reader.LoadMoreTokens(start, end); } } return(sequence); }
// Support the built-in '=' function. False until explicitly proven otherwise. public static MalVal EQ(MalVal a, MalVal b) { if (a.GetType() != b.GetType()) { // TODO - allow equality comparisons between ints and floats. return(malFalse); } // If here, they are of the same Mal type. Do they have the same value? switch ((object)a) { case MalSym aSym: if (aSym.getName() == ((MalSym)b).getName()) { return(malTrue); } break; case MalNum aNumk: if (aNumk == ((MalNum)b)) { return(malTrue); } break; case MalString aString: if (aString.ToString() == ((MalString)b).ToString()) { return(malTrue); } break; case MalKeyword aKeyWord: if (aKeyWord.ToString() == ((MalKeyword)b).ToString()) { return(malTrue); } break; case MalSeq aSeq: // Sequences must be the same length, and each element must be the same. MalSeq bSeq = (MalSeq)b; if (aSeq.Count() != bSeq.Count()) { // They are not of equal length. return(malFalse); } for (var i = 0; i < aSeq.Count(); i++) { // At least one of the elements is not equal. if (EQ(aSeq[i], bSeq[i]) == malFalse) { return(malFalse); } } return(malTrue); case MalAtom aAtom: // The atoms must be the same object. Two atoms containing the same value are not equal. // TODO check whether this should be true if dereferencing them should be used instead. This isn't specified in the tests. if (aAtom == ((MalAtom)b)) { return(malTrue); } break; default: throw new MalInternalError("Can't yet compare '" + a.GetType() + "' with '" + b.GetType() + "'"); } return(malFalse); }