Example #1
0
        static void Main(string[] args)
        {
            ProgramArguments PArgs = ReadArguments(args);

            if (PArgs.Help)
            {
                Console.WriteLine("Usage: executable [-I] [-E evaluator] [-T] [-t] [-d] [file1 file2 ..] [-help]");
                Console.WriteLine("");
                Console.WriteLine("Where:");
                Console.WriteLine("\t-I            Enter interactive (REPL) mode. Default if no files specified.");
                Console.WriteLine("\t-E evaluator  Use given evaluator, valid options: cell, classic, frame");
                Console.WriteLine("\t-T            Run tests");
                Console.WriteLine("\t-t            Enable timing");
                Console.WriteLine("\t-d            Enable instruction debugging");
                Console.WriteLine("\tfile1..       File to run");
                Console.WriteLine("\t-help         Show this help");
                Console.WriteLine("");
                Console.WriteLine("Evaluators:");
                Console.WriteLine("\tframe         Frame evaluator. Combines cell and classic benefits. Default.");
                Console.WriteLine("\tcell          Cell virtual machine.");
                Console.WriteLine("\tclassic       Classic eval loop, no multitasking.");
                return;
            }

            Debug       = PArgs.Debug;
            ShowTimings = PArgs.Timing;
            Evaluator   = Activator.CreateInstance(PArgs.EvaluatorType) as ISchemeEval;

            SchemeEnvironment env = new SchemeEnvironment();

            StandardRuntime.AddGlobals(env);
            AddProgramGlobals(env);

            if (PArgs.Tests)
            {
                RunTests();
            }
            else if (PArgs.Files.Count == 0)
            {
                PArgs.Interactive = true;
            }

            if (PArgs.Files.Count > 0)
            {
                foreach (string file in PArgs.Files)
                {
                    RunSpecifiedFile(file, env);
                }
            }
            if (PArgs.Interactive)
            {
                REPL(env);
            }
            else if (System.Diagnostics.Debugger.IsAttached)
            {
                Console.WriteLine("[DEBUG] Press ENTER to end.");
                Console.ReadLine();
            }
        }
Example #2
0
        static void AddProgramGlobals(SchemeEnvironment env)
        {
            List <Cell> history = new List <Cell>();
            bool        quit    = false;
            bool        timing  = false;

            // Add a function to get a history result
            env.Insert("h", new Cell(args => new Cell(history[(int)(args[0])])));
            env.Insert("eval", new Cell((args, subenv) => {
                if (args.Length > 1)
                {
                    subenv = args[1].Environment;
                }
                return(DoEval(new Cell(args[0]), subenv));
            }));
            env.Insert("env", new Cell((args, subenv) => new Cell(subenv)));
            env.Insert("str", new Cell(args => new Cell(args[0].ToString())));
            env.Insert("env-str", new Cell(args => new Cell(args[0].Environment.ToString())));
            env.Insert("exit", new Cell(args => { quit = true; return(StandardRuntime.Nil); }));
            env.Insert("quit", env.Lookup(new Cell("exit")));
            env.Insert("timing", new Cell(args => {
                if (args.Length > 0)
                {
                    timing = ((string)args[0] == "on" || args[0] == StandardRuntime.True);
                    Console.Error.WriteLine("Timing is now " + (timing ? "on" : "off"));
                }
                return(timing ? StandardRuntime.True : StandardRuntime.False);
            }));

            // Add evaluator constants
            env.Insert("evcell", new Cell("evcell"));
            env.Insert("evclassic", new Cell("evclassic"));
            env.Insert("evframe", new Cell("evframe"));
            // Add function to change evaluator
            env.Insert("sweval", new Cell(args => {
                if (args.Length == 0)
                {
                    if (Evaluator.GetType() == typeof(CellMachineEval))
                    {
                        return(new Cell("evcell"));
                    }
                    else if (Evaluator.GetType() == typeof(StandardEval))
                    {
                        return(new Cell("evclassic"));
                    }
                    else if (Evaluator.GetType() == typeof(FrameEval))
                    {
                        return(new Cell("evframe"));
                    }
                    else
                    {
                        throw new InvalidDataException();
                    }
                }

                ISchemeEval newEvaluator;
                Cell result;
                switch (args[0].Value)
                {
                case "evcell":
                    newEvaluator = new CellMachineEval();
                    result       = new Cell("evcell");
                    break;

                case "evclassic":
                    newEvaluator = new StandardEval();
                    result       = new Cell("evclassic");
                    break;

                case "evframe":
                    newEvaluator = new FrameEval();
                    result       = new Cell("evframe");
                    break;

                default:
                    return(new Cell("#invalid_argument"));
                }

                // Copy details to new evaluator
                newEvaluator.Debug = Evaluator.Debug;
                Evaluator          = newEvaluator;

                return(result);
            }));
            // Add function to run unit tests on evaluator
            env.Insert("swtest", new Cell(args => {
                var results = SchemeEval.RunTests(Evaluator);
                Cell result = new Cell(CellType.LIST);
                result.ListValue.Add(new Cell(results.Success));
                result.ListValue.Add(new Cell(results.Failures));
                return(result);
            }));

            env.Insert("help", new Cell(args => {
                Console.Write("SchemingSharply v {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version);
#if DEBUG
                Console.WriteLine(" debug");
#else
                Console.WriteLine(" release");
#endif
                Console.WriteLine("Type `quit' or `\\q' to quit");
                Console.WriteLine("Type `(env-str (env))' to display environment");
                //Console.WriteLine("Use `(eval expr)' or `(eval expr (env))' for testing");
                Console.WriteLine("Use `(h n)' to view history item n");
                Console.WriteLine("Use `(timing #true)` to enable timing, `(debug #true)` to enable debugging");
                Console.WriteLine("Use `(sweval ...)` to get or set evaluator; valid options: evcell, evclassic, evframe");
                Console.WriteLine("Use `(swtest)` to run unit tests");
                Console.WriteLine("Use `(help)' to display this message again");
                Console.WriteLine();
                return(StandardRuntime.Nil);
            }));
            env.Insert("repl", new Cell(args => {
                quit = false;
                while (!quit)
                {
                    int index    = history.Count;
                    string entry = ReadLine(string.Format("{0}> ", index)).Trim();
                    if (entry.Equals("quit", StringComparison.OrdinalIgnoreCase) ||
                        entry.Equals("exit", StringComparison.OrdinalIgnoreCase) ||
                        entry == "\\q")
                    {
                        break;
                    }
                    if (entry.Equals(""))
                    {
                        continue;
                    }
                    try {
                        Stopwatch sw = new Stopwatch();
                        sw.Start();
                        Cell entered      = StandardRuntime.Read(entry);
                        LastExecutedSteps = Evaluator.Steps;
                        Cell result       = DoEval(entered, env);
                        string steps      = (Evaluator.Steps - LastExecutedSteps).ToString();
                        if (Evaluator.Steps < LastExecutedSteps)
                        {
                            steps = "??";
                        }
                        sw.Stop();
                        Console.WriteLine("===> {0}", result);
                        if (timing)
                        {
                            Console.WriteLine("=== Executed {0} steps in {1}ms", steps, sw.ElapsedMilliseconds);
                        }
                        history.Add(result);
                    } catch (Exception e) {
                        Console.WriteLine("!!!> {0}", e.Message);
                    }
                }
                return(StandardRuntime.Nil);
            }));
        }
Example #3
0
        public static TestResults RunTests(ISchemeEval evalClass, bool display = true)
        {
            int success = 0, failures = 0;

            SchemeEnvironment env = new SchemeEnvironment();

            StandardRuntime.AddGlobals(env);
            Func <Cell, Cell>   EvalCell   = (Cell x) => evalClass.Eval(x, env);
            Func <string, Cell> EvalString = (string x) => {
                Cell code = StandardRuntime.Read(x);
                return(evalClass.Eval(code, env));
            };
            Func <Cell, Cell, bool> AssertEqual = (Cell a, Cell b) => {
                if (a.ToString() != b.ToString())
                {
                    string message = string.Format("{0} != {1}", a, b);
                    Console.WriteLine("Assertion failed: {0}", message);
                    //Debug.Assert(false, message);
                    failures++;
                    return(false);
                }
                else
                {
                    //Console.WriteLine("Success : {0} = {1}", a, b);
                    success++;
                    return(true);
                }
            };

            // Core tests
            //if (true) goto unit;
            Console.WriteLine("Core tests=======");
            if (1 == 1)
            {
                AssertEqual(EvalString(StandardRuntime.True.Value), StandardRuntime.True);
            }
            if (1 == 1)
            {
                AssertEqual(EvalString("1"), new Cell(1));
            }
            if (1 == 1)
            {
                AssertEqual(EvalCell(new Cell(new Cell[] { })), StandardRuntime.Nil);
            }
            if (1 == 1)
            {
                AssertEqual(EvalString("()"), StandardRuntime.Nil);
            }
            if (1 == 1)
            {
                AssertEqual(EvalString("(quote 1 2 3)"), new Cell(1));
            }
            if (1 == 1)
            {
                AssertEqual(EvalString("(define x 123)"), new Cell(123));
            }
            if (1 == 1)
            {
                AssertEqual(EvalString("x"), new Cell(123));
            }
            if (1 == 1)
            {
                AssertEqual(EvalString("(set! x 456)"), new Cell(456));
            }
            if (1 == 1)
            {
                AssertEqual(EvalString("x"), new Cell(456));
            }
            if (1 == 1)
            {
                AssertEqual(EvalString("(lambda (x y) (+ x y))"), new Cell("#Lambda((x y) (+ x y))"));
            }
            if (1 == 1)
            {
                AssertEqual(EvalString("(begin (define y 789) y)"), new Cell(789));
            }
            if (1 == 1)
            {
                AssertEqual(EvalString("(+ 1 2)"), new Cell(3));
            }
            if (1 == 1)
            {
                AssertEqual(EvalString("(begin (define add (lambda (x y) (+ x y))) (add 1 2))"), new Cell(3));
            }
            if (1 == 1)
            {
                AssertEqual(EvalString("(if (= 1 1) 1 0)"), new Cell("1"));
            }
            if (1 == 1)
            {
                AssertEqual(EvalString("(if (= 0 1) 0 1)"), new Cell("1"));
            }
            if (1 == 1)
            {
                AssertEqual(EvalString("(if (= 1 1) 1)"), new Cell("1"));
            }
            if (1 == 1)
            {
                AssertEqual(EvalString("(if (= 1 0) 1)"), StandardRuntime.Nil);
            }
            if (1 == 1)
            {
                AssertEqual(EvalString("(if (= 1 1) (+ 1 1) (- 1 1))"), new Cell(2));
            }
            if (1 == 1)
            {
                AssertEqual(EvalString("(if (= 1 1) (begin 1) (- 1 1))"), new Cell(1));
            }
            Console.WriteLine("Core tests: passed {0}, failed {1}", success, failures);

unit:
            // Unit tests
            Console.WriteLine("Unit tests=======");
            Action <string, string> TEST = (string code, string expected) => {
                if (AssertEqual(EvalString(code), new Cell(expected)))
                {
                    Console.WriteLine("PASS: {0} == {1}", code, expected);
                }
                else
                {
                    Console.WriteLine("FAIL: {0}", code);
                }
            };

            TEST("((lambda (X) (+ X X)) 5)", "10");
            TEST("(< 10 2)", "#false");
            TEST("(<= 10 2)", "#false");
            //TEST("(quote \"f\\\"oo\")", "f\\\"oo");
            //TEST("(quote \"foo\")", "foo");
            //TEST("(quote (testing 1 (2.0) -3.14e159))", "(testing 1 (2.000000e+00) -3.140000e+159)");
            TEST("(+ 2 2)", "4");
            //TEST("(+ 2.5 2)", "4.500000e+00");
            //TEST("(* 2.25 2)", "4.500000e+00");    // Bugfix, multiplication was losing floating point value
            TEST("(+ (* 2 100) (* 1 10))", "210");
            TEST("(> 6 5)", "#true");
            TEST("(< 6 5)", "#false");
            TEST("(if (> 6 5) (+ 1 1) (+ 2 2))", "2");
            TEST("(if (< 6 5) (+ 1 1) (+ 2 2))", "4");
            TEST("(define X 3)", "3");
            TEST("X", "3");
            TEST("(+ X X)", "6");
            TEST("(begin (define X 1) (set! X (+ X 1)) (+ X 1))", "3");
            TEST("(define twice (lambda (X) (* 2 X)))", "#Lambda((X) (* 2 X))");
            TEST("(twice 5)", "10");
            TEST("(define compose (lambda (F G) (lambda (X) (F (G X)))))", "#Lambda((F G) (lambda (X) (F (G X))))");
            TEST("((compose list twice) 5)", "(10)");
            TEST("(define repeat (lambda (F) (compose F F)))", "#Lambda((F) (compose F F))");
            TEST("((repeat twice) 5)", "20");
            TEST("((repeat (repeat twice)) 5)", "80");
            // Factorial - head recursive
            TEST("(define fact (lambda (N) (if (<= N 1) 1 (* N (fact (- N 1))))))", "#Lambda((N) (if (<= N 1) 1 (* N (fact (- N 1)))))");
            TEST("(fact 3)", "6");
            // TODO: Bignum support
            TEST("(fact 12)", "479001600");
            // Factorial - tail recursive
            TEST("(begin (define fac (lambda (N) (fac2 N 1))) (define fac2 (lambda (N A) (if (<= N 0) A (fac2 (- N 1) (* N A))))))", "#Lambda((N A) (if (<= N 0) A (fac2 (- N 1) (* N A))))");
            //TEST("(fac 50.1)", "4.732679e+63");   // Bugfix, multiplication was losing floating point value
            TEST("(define abs (lambda (N) ((if (> N 0) + -) 0 N)))", "#Lambda((N) ((if (> N 0) + -) 0 N))");
            TEST("(list (abs -3) (abs 0) (abs 3))", "(3 0 3)");
            TEST("(define combine (lambda (F) " +
                 "(lambda (X Y) " +
                 "(if (null? X) (quote ()) " +
                 "(F (list (head X) (head Y)) " +
                 "((combine F) (tail X) (tail Y)))))))", "#Lambda((F) (lambda (X Y) (if (null? X) (quote ()) (F (list (head X) (head Y)) ((combine F) (tail X) (tail Y))))))");
            TEST("(define zip (combine cons))", "#Lambda((X Y) (if (null? X) (quote ()) (F (list (head X) (head Y)) ((combine F) (tail X) (tail Y)))))");
            TEST("(zip (list 1 2 3 4) (list 5 6 7 8))", "((1 5) (2 6) (3 7) (4 8))");
            TEST("(define riff-shuffle (lambda (Deck) (begin " +
                 "(define take (lambda (N Seq) (if (<= N 0) (quote ()) (cons (head Seq) (take (- N 1) (tail Seq)))))) " +
                 "(define drop (lambda (N Seq) (if (<= N 0) Seq (drop (- N 1) (tail Seq))))) " +
                 "(define mid (lambda (Seq) (/ (length Seq) 2))) " +
                 "((combine append) (take (mid Deck) Deck) (drop (mid Deck) Deck)))))", "#Lambda((Deck) (begin (define take (lambda (N Seq) (if (<= N 0) (quote ()) (cons (head Seq) (take (- N 1) (tail Seq)))))) (define drop (lambda (N Seq) (if (<= N 0) Seq (drop (- N 1) (tail Seq))))) (define mid (lambda (Seq) (/ (length Seq) 2))) ((combine append) (take (mid Deck) Deck) (drop (mid Deck) Deck))))");
            TEST("(riff-shuffle (list 1 2 3 4 5 6 7 8))", "(1 5 2 6 3 7 4 8)");
            TEST("((repeat riff-shuffle) (list 1 2 3 4 5 6 7 8))", "(1 3 5 7 2 4 6 8)");
            TEST("(riff-shuffle (riff-shuffle (riff-shuffle (list 1 2 3 4 5 6 7 8))))", "(1 2 3 4 5 6 7 8)");

            Console.WriteLine("Macro tests=======");
            //TEST("(define do (macro (expr) (expr)))", "#Macro");
            TEST("(define abc 1)", "1");
            TEST("(define get! (macro (var) var)))", "#Macro((var) var)");
            TEST("(get! abc)", "1");
            TEST("(define incr (macro (var n) (list (quote set!) var (list (quote +) n (list (quote get!) var)))))", "#Macro((var n) (list (quote set!) var (list (quote +) n (list (quote get!) var))))");
            TEST("(incr abc 2)", "3");
            TEST("(get! abc)", "3");

            // Repositional end marker for specific unit testing
            goto end;

end:
            if (display)
            {
                if (failures > 0)
                {
                    Console.WriteLine("TEST FAILURES OCCURRED");
                }
                Console.WriteLine("{0} success, {1} failures", success, failures);
            }

            return(new TestResults(success, failures));
        }