Beispiel #1
0
        // Return the value of a target symbol in this or an outer scope.
        public JKLVal Get(JKLSym keySymbol)
        {
            Env e = Find(keySymbol);

            if (e == null)
            {
                switch (keySymbol.ToString(true))
                {
                // Some symbols are only valid when used in a particular context.

                case "unquote":
                    throw new JKLEvalError("'unquote' used incorrectly (missing macro?)");

                case "quasiquote":
                    throw new JKLEvalError("'quasiquote' used incorrectly (missing macro?)");

                case "splice-unquote":
                    throw new JKLEvalError("'splice-unquote' used incorrectly (missing macro?)");
                }
                //// If here the symbol simply hasn't been defined or is mis-spelt.
                throw new JKLLookupError("Get - Symbol not found '" + keySymbol.ToString(true) + "'");
            }
            else
            {
                if (e.data.TryGetValue(keySymbol.getName(), out JKLVal value))
                {
                    return(value);
                }
                else
                {
                    throw new JKLInternalError("Get - Find successful but symbol retrieval failed '" + keySymbol.ToString(true) + "'");
                }
            }
        }
Beispiel #2
0
 public void Set(JKLSym keySymbol, JKLVal value)
 {
     // Takes a symbol key and a JKL value and adds them to the environment.
     if (!data.TryAdd(keySymbol.getName(), value))
     {
         // Symbol can shadow an equivalent in an outer scope but cannot be duped.
         throw new JKLEvalError("Attempt to redefine '" + keySymbol.ToString(true) + "'");
     }
 }
Beispiel #3
0
 // Search for and return the environment (scope) that contains a target symbol.
 public Env Find(JKLSym keySymbol)
 {
     if (data.ContainsKey(keySymbol.getName()))
     {
         // Symbol exists in the current scope.
         return(this);
     }
     else if (outer != null)
     {
         // Recurse to search for the symbol in an outer scope.
         return(outer.Find(keySymbol));
     }
     else
     {
         // Symbol is not defined.
         return(null);
     }
 }
Beispiel #4
0
        // Setup the REPL.
        public REPL()
        {
            // Load built-in functions into the initial eval environment.
            try
            {
                myEnv = new Env(null);

                // Load core functions.
                foreach (var thing in JKLNameSpace)
                {
                    JKLSym mSym = new JKLSym(thing.Key);

                    if (myEnv.Find(mSym) == null)
                    {
                        myEnv.Set(mSym, thing.Value);
                    }
                    else
                    {
                        // The namespace itself may already have thrown an error but if not.
                        throw new JKLInternalError("Attempt to refine symbol: '" + mSym.ToString(true) + "' with '" + thing.Value.ToString(true) + "'");
                    }
                }
                // Load the special eval core function. We have to do it here to access the REPL env.
                myEnv.Set(new JKLSym("eval"), new JKLFunc(args =>
                {
                    return(EVAL(args[0], myEnv));
                }));

                ////                EVAL(READ("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"))\")))))"), myEnv);
                //myEnv.Set(new JKLSym("load-file"), new JKLFunc(args =>
                //{
                //    if (args[0] is JKLString mStr)
                //    {
                //        try
                //        {
                //            string FileText = File.ReadAllText(mStr.unbox());

                //            // Ee have the text of the file. Now build a file loader to eval.
                //            StringBuilder sb = new StringBuilder();
                //            sb.Append("(do ");
                //            sb.Append(FileText);
                //            sb.Append(") ");


                //            return EVAL(read_str(sb.ToString()), myEnv);
                //        }
                //        catch (Exception e)
                //        {
                //            throw new JKLEvalError("slurp: " + e.Message);
                //        }
                //    }
                //    throw new JKLEvalError("load-file: expected filename but got '" + args[0] + "'");

                //}));


                // Add 'core' functions defined using JKL itself.

                EVAL(READ("(def! *ARGV* (list))"), myEnv);

                EVAL(READ("(def! not (fn* (a) (if a false true)))"), myEnv);

                // Establish a gensym mechanism
                EVAL(READ("(def! *gensym-counter* (atom 0))"), myEnv);
                EVAL(READ("(def! gensym (fn* [] (symbol (str \"G__\" (swap! *gensym-counter* (fn* [x] (+ 1 x)))))))"), myEnv);

                // This differs from the reference in that it uses a JKL-specific function slurp-do to
                // avoid the string quoting problem that can occur when trying to add a (do ... ) form
                // around the text retuned by raw slurp.
                EVAL(READ("(def! load-file (fn* (f) (eval (read-string (slurp-do f)))))"), myEnv);

                EVAL(READ("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))"), myEnv);

                EVAL(READ("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) (let* (condvar (gensym)) `(let* (~condvar ~(first xs)) (if ~condvar ~condvar (or ~@(rest xs)))))))))"), myEnv);
            }
            catch (System.TypeInitializationException e)
            {
                // Typically happens if there is a duplicate symbol in the namespace list
                Console.WriteLine("Unrecoverable error: " + e.InnerException.Message);
            }
            catch (JKLLookupError e)
            {
                Console.WriteLine(e.Message);
            }
            catch (JKLEvalError e)
            {
                Console.WriteLine(e.Message);
            }
            catch (JKLParseError e)
            {
                Console.WriteLine(e.Message);
            }
        }