예제 #1
0
        // Read a MalVal form - which is either an atom or a sequence.
        static public MalVal read_form(Reader reader)
        {
            if (reader.Peek() == null)
            {
                // Reader is empty - caused by a comment line in the input.
                return(null);
            }
            else if (reader.Peek().StartsWith('\''))
            {
                // Create a list containing the quote symbol and the quoted form.
                // Skip the quote symbol.
                reader.Next();

                // Now read the quoted thing, and build a quote form.
                return(new MalList(new MalQuote(), read_form(reader)));
                // TODO handle quasiquotes and splices in the same way.
            }
            else if (reader.Peek().StartsWith('('))
            {
                // Create a new List and read it's body.
                return(read_list(reader, new MalList(), '(', ')'));
            }
            else if (reader.Peek().StartsWith('['))
            {
                // Create a new Vector and read it's body.
                return(read_list(reader, new MalVector(), '[', ']'));
            }
            else if (reader.Peek().StartsWith('{'))
            {
                // Create a new HashMap and read it's body.
                // TODO - check that hashmap contains a list of keywords and values.
                return(read_list(reader, new MalHashMap(), '{', '}'));
            }
            else if (reader.Peek().StartsWith(')') || reader.Peek().StartsWith(']') || reader.Peek().StartsWith('}'))
            {
                // A sequence close character that doesn't match a start.
                // This correctly handles a case like [1 ( 2 ] 3).
                throw new MalParseError("Expecting sequence or atom but got '" + reader.Peek() + "'");
            }
            else
            {
                // This isn't a list try so parse it as an atom.
                return(read_atom(reader));
            }
        }
예제 #2
0
        // 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 MalSeqBase read_list(Reader reader, MalSeqBase 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);
        }
예제 #3
0
        // Read a MalVal form - which is either an atom or a sequence.
        static public MalVal read_form(Reader reader)
        {
            if (reader.Peek() == null)
            {
                // Reader is empty - caused by a comment line in the input.
                return(null);
            }
            else if (reader.Peek().StartsWith('('))
            {
                // Create a new List and read it's body.
                return(read_list(reader, new MalList(), '(', ')'));
            }
            else if (reader.Peek().StartsWith('['))
            {
                // Create a new Vector and read it's body.
                return(read_list(reader, new MalVector(), '[', ']'));
            }
            else if (reader.Peek().StartsWith('{'))
            {
                // Create a new HashMap and read it's body. EVAL checks it has valid key val pairs.
                return(read_list(reader, new MalHashMap(), '{', '}'));
            }
            else if (reader.Peek().StartsWith(')') || reader.Peek().StartsWith(']') || reader.Peek().StartsWith('}'))
            {
                // A sequence close character that doesn't match a start.
                // This correctly handles a case like [1 ( 2 ] 3).
                throw new MalParseError("Expecting sequence or atom but got '" + reader.Peek() + "'");
            }
            else if (reader.Peek().StartsWith('&'))
            {
                // Reader macro. We have '&atomName'. Convert this into (deref atomName);
                string atomToDeref = reader.Peek();
                if (atomToDeref.Length == 1)
                {
                    // Treat a solo '&' as a varargs symbol,
                    reader.Next();
                    return(malVarArgsChar);
                }
                // Build a deref form, extracting the atom name from the token.
                MalList derefForm = new MalList();
                derefForm.Add(new MalSym("deref"));
                derefForm.Add(new MalSym(atomToDeref.Substring(1)));
                // TODO - ??? handle non-explicit atom names? E.g. where '&' is followed by a form that creates an atom name.

                // Advance past the deref symbol and return the new form.
                reader.Next();
                return(derefForm);
            }
            else if (reader.Peek().StartsWith('\''))
            {
                // Return a list containing a quote symbol and the quoted form.
                reader.Next();
                MalList quoteForm = new MalList();
                quoteForm.Add(new MalSym("quote"));
                quoteForm.Add(read_form(reader));
                return(quoteForm);
            }
            else if (reader.Peek().StartsWith('`'))
            {
                // Return a list containing a quasiquote symbol and the quasiquoted form.
                reader.Next();
                MalList quasiquoteForm = new MalList();
                quasiquoteForm.Add(new MalSym("quasiquote"));
                quasiquoteForm.Add(read_form(reader));
                return(quasiquoteForm);
            }
            else if (reader.Peek().StartsWith("~@"))
            {
                // Return a list containing a splice-unquote symbol and the next form.
                // Dammit! I'd missed the '~' here and spent several days wondering why (or ...) didn't work.
                reader.Next();
                MalList quasiquoteForm = new MalList();
                quasiquoteForm.Add(new MalSym("splice-unquote"));
                quasiquoteForm.Add(read_form(reader));
                return(quasiquoteForm);
            }
            else if (reader.Peek().StartsWith('~'))
            {
                // Return a list containing an unquote symbol and the next form.
                reader.Next();
                MalList quasiquoteForm = new MalList();
                quasiquoteForm.Add(new MalSym("unquote"));
                quasiquoteForm.Add(read_form(reader));
                return(quasiquoteForm);
            }


            else
            {
                // This isn't a list so parse it as an atom.
                return(read_token(reader));
            }
        }
예제 #4
0
        // Read a MalVal form - which is either an atom or a sequence.
        static public MalVal read_form(Reader reader)
        {
            if (reader.Peek() == null)
            {
                // Reader is empty - caused by a comment line in the input.
                return(null);
            }
            else if (reader.Peek().StartsWith('('))
            {
                // Create a new List and read it's body.
                return(read_list(reader, new MalList(), '(', ')'));
            }
            else if (reader.Peek().StartsWith('['))
            {
                // Create a new Vector and read it's body.
                return(read_list(reader, new MalVector(), '[', ']'));
            }
            else if (reader.Peek().StartsWith('{'))
            {
                // Create a new HashMap and read it's body. EVAL checks it has valid key val pairs.
                return(read_list(reader, new MalHashMap(), '{', '}'));
            }
            else if (reader.Peek().StartsWith(')') || reader.Peek().StartsWith(']') || reader.Peek().StartsWith('}'))
            {
                // A sequence close character that doesn't match a start.
                // This correctly handles a case like [1 ( 2 ] 3).
                throw new MalParseError("Expecting sequence or atom but got '" + reader.Peek() + "'");
            }
            else if (reader.Peek().StartsWith('&'))
            {
                // Reader macro. We have '&atomName'. Convert this into (deref atomName);
                string atomToDeref = reader.Peek();
                if (atomToDeref.Length == 1)
                {
                    throw new MalParseError("'&' lacks atom name");
                }
                // Build a deref form, extracting the atom name from the token.
                MalList derefForm = new MalList();
                derefForm.Add(new MalSym("deref"));
                derefForm.Add(new MalSym(atomToDeref.Substring(1)));
                // TODO - ??? handle non-explicit atom names? E.g. where '&' is followed by a form that creates an atom name.

                // Advance past the deref symbol and return the new form.
                reader.Next();
                return(derefForm);
            }
            else if (reader.Peek().StartsWith('\''))
            {
                // Create a list containing the quote symbol and the quoted form.
                // Skip the quote symbol.
                reader.Next();

                MalList quoteForm = new MalList();
                quoteForm.Add(new MalQuote());
                quoteForm.Add(read_form(reader));

                // Now read the quoted thing, and build a quote form.
                return(quoteForm);
                // TODO handle quasiquotes and splices in the same way.
            }
            else
            {
                // This isn't a list so parse it as an atom.
                return(read_token(reader));
            }
        }