Esempio n. 1
0
 //------------------ General utilities -------------------------------------------
 // Generic error check for core fns.
 public static void CheckArgCount(JKLList args, int expectedCount, string callerName)
 {
     if (args.Count() != expectedCount)
     {
         throw new JKLEvalError("'" + callerName + "' expected " + expectedCount + " arg(s) but got " + args.Count());
     }
 }
Esempio n. 2
0
        // Name changed from the guide to highlight that the outcome is complicated.
        static JKLVal Quasiquote(JKLVal ast)
        {
            if (!is_pair(ast))
            {
                // Case 1.
                // If is_pair of ast is false: return a new list containing: a symbol named "quote" and ast.
                JKLList qList = new JKLList();

                qList.Add(new JKLSym("quote"));
                qList.Add(ast);

                //qList.Conj(new JKLSym("quote"), ast);
                return(qList);
            }
            else
            {
                JKLSequence astSeq = (JKLSequence)ast;
                JKLVal      a0     = astSeq[0];

                // Case 2:  if the first element of ast is a symbol named "unquote": return the second element of ast.
                if (a0 is JKLSym a0Sym && a0Sym.getName() == "unquote")
                {
                    // (qq (uq form)) -> form
                    return(astSeq[1]);
                }
Esempio n. 3
0
            // Analagous to the C# equivalent, shallow copy of a JKLList.
            public JKLList GetRange(int first, int last)
            {
                if (first > last)
                {
                    throw new JKLInternalError("GetRange - first '" + first + "' must be less than or equal to '" + last + "'");
                }
                JKLList newList = new JKLList();

                for (var i = 0; i < MyElements.Count; i++)
                {
                    if (i >= first && i <= last)
                    {
                        newList.Add(MyElements[i]);
                    }
                }

                return(newList);
            }
Esempio n. 4
0
            // Return the tail of the list.
            public JKLList Rest()
            {
                if (MyElements.Count > 0)
                {
                    // We return a JKLList, not a List<JKLVal>.
                    JKLList newList = new JKLList();

                    foreach (var element in MyElements.GetRange(1, MyElements.Count - 1))
                    {
                        newList.Add(element);
                    }
                    return(newList);
                }
                else
                {
                    return(new JKLList());
                }
            }
Esempio n. 5
0
            // Non-destructively remove a target item from a supplied list.
            // This has CL-like semantics, do only removes the first target encountered.
            public JKLSequence Remove(JKLVal target)
            {
                // Create a list to which the non-target items will be copied.
                JKLSequence RemoveSeq;
                bool        removedP = false;

                // Instantiate a sequence of the same type.
                if (this is JKLList)
                {
                    RemoveSeq = new JKLList();
                }
                else if (this is JKLVector)
                {
                    RemoveSeq = new JKLVector();
                }
                else
                {
                    throw new JKLEvalError("remove expected list or vector but got '" + this.ToString() + "'");
                }
                for (var i = 0; i < MyElements.Count; i++)
                {
                    if (removedP)
                    {
                        // target already removed so always okay to keep this one.
                        RemoveSeq.Add(MyElements[i]);
                    }
                    else
                    {
                        if (EQ(MyElements[i], target) == jklTrue)
                        {
                            // This is the target to remove, so don't copy it.
                            removedP = true;
                        }
                        else
                        {
                            RemoveSeq.Add(MyElements[i]);
                        }
                    }
                }
                return(RemoveSeq);
            }
Esempio n. 6
0
        // Read a JKLVal form - which is either an atom or a sequence.
        static public JKLVal read_form(TokenQueue TQ)
        {
            if (TQ.Peek() == null)
            {
                // Reader is empty - caused by a comment line in the input.
                return(null);
            }
            else if (TQ.Peek().StartsWith('('))
            {
                // Create a new List and read it's body.
                return(read_list(TQ, new JKLList(), '(', ')'));
            }
            else if (TQ.Peek().StartsWith('['))
            {
                // Create a new Vector and read it's body.
                return(read_list(TQ, new JKLVector(), '[', ']'));
            }
            else if (TQ.Peek().StartsWith('{'))
            {
                // Create a new HashMap and read it's body. EVAL checks it has valid key val pairs.
                return(read_list(TQ, new JKLHashMap(), '{', '}'));
            }
            else if (TQ.Peek().StartsWith(')') || TQ.Peek().StartsWith(']') || TQ.Peek().StartsWith('}'))
            {
                // A sequence close character that doesn't match a start.
                // This correctly handles a case like [1 ( 2 ] 3).
                throw new JKLParseError("Expecting sequence or atom but got '" + TQ.Peek() + "'");
            }

            else if (TQ.Peek().StartsWith('&'))
            {
                // Reader macro. We have '&atomName'. Convert this into (deref atomName);
                string varArgAtom = TQ.Peek();
                if (varArgAtom.Length == 1)
                {
                    // Treat a solo '&' as a varargs symbol,
                    TQ.Next();
                    return(jklVarArgsChar);
                }
                else
                {
                    throw new JKLParseError("'&' can't start a symbol name: '" + varArgAtom.ToString() + "'");
                }
            }
            else if (TQ.Peek().StartsWith('@'))
            {
                TQ.Next();
                // Build a deref form.
                JKLList derefForm = new JKLList();
                derefForm.Add(new JKLSym("deref"));
                derefForm.Add(read_form(TQ));
                return(derefForm);
            }
            else if (TQ.Peek().StartsWith('\''))
            {
                // Return a list containing a quote symbol and the quoted form.
                TQ.Next();
                JKLList quoteForm = new JKLList();
                quoteForm.Add(new JKLSym("quote"));
                quoteForm.Add(read_form(TQ));
                return(quoteForm);
            }
            else if (TQ.Peek().StartsWith('`'))
            {
                // Return a list containing a quasiquote symbol and the quasiquoted form.
                TQ.Next();
                JKLList quasiquoteForm = new JKLList();
                quasiquoteForm.Add(new JKLSym("quasiquote"));
                quasiquoteForm.Add(read_form(TQ));
                return(quasiquoteForm);
            }
            else if (TQ.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.
                TQ.Next();
                JKLList quasiquoteForm = new JKLList();
                quasiquoteForm.Add(new JKLSym("splice-unquote"));
                quasiquoteForm.Add(read_form(TQ));
                return(quasiquoteForm);
            }
            else if (TQ.Peek().StartsWith('~'))
            {
                // Return a list containing an unquote symbol and the next form.
                TQ.Next();
                JKLList quasiquoteForm = new JKLList();
                quasiquoteForm.Add(new JKLSym("unquote"));
                quasiquoteForm.Add(read_form(TQ));
                return(quasiquoteForm);
            }
            else if (TQ.Peek().StartsWith('^'))
            {
                // Return a new list that contains the symbol "with-meta" and the result of reading the
                // next next form (2nd argument) (read_form) and the next form (1st argument) in that order
                TQ.Next();
                JKLList withMetaForm = new JKLList();
                withMetaForm.Add(new JKLSym("with-meta"));
                JKLVal firstArg  = read_form(TQ);
                JKLVal secondArg = read_form(TQ);
                withMetaForm.Add(secondArg);
                withMetaForm.Add(firstArg);
                return(withMetaForm);
            }
            else
            {
                // This isn't a list so parse it as an atom.
                return(read_token(TQ));
            }
        }
Esempio n. 7
0
 // Call the stored func, passing it a list containing args, if any.
 public JKLVal Apply(JKLList args)
 {
     //                Console.Write("applying function built-in = " + myCreatedByFn);
     return(fn(args));
 }