Exemplo n.º 1
0
        public void ExecutionCannotBeHaltedWhenEvaluatingFromWithinANativeFunction()
        {
            var host = new LispHost();

            host.AddFunction("NATIVE-FUNCTION", (host, executionState, args) =>
            {
                var result = host.EvalAtStackFrame(executionState.StackFrame, LispList.FromEnumerable(new LispObject[] { LispSymbol.CreateFromString("*"), new LispInteger(2), new LispInteger(2) }));
                return(result);
            });
            var hitBreakpoint = false;

            host.RootFrame.EvaluatingExpression += (s, e) =>
            {
                if (!hitBreakpoint &&
                    e.Expression is LispList list &&
                    list.ToString() == "(* 2 2)")
                {
                    hitBreakpoint   = true;
                    e.HaltExecution = true; // this should not be honored
                }
            };
            var evalResult = host.Eval("(native-function)");

            Assert.True(hitBreakpoint);
            Assert.True(evalResult.ExecutionState.IsExecutionComplete);
            Assert.Equal(4, ((LispInteger)evalResult.LastResult).Value);
        }
Exemplo n.º 2
0
        public void ExternalFunction()
        {
            var host = new LispHost();

            host.AddFunction("ADD", (host, executionState, args) => (LispInteger)args[0] + (LispInteger)args[1]);
            Assert.Equal(new LispInteger(3), host.Eval("(add 1 2)").LastResult);
        }
Exemplo n.º 3
0
        public void TailCallWithIf()
        {
            var host = new LispHost(useTailCalls: true);
            var lastInterpreterStackDepth = 0;
            var lastDotNetStackDepth      = 0;
            var invocationCount           = 0;
            var maxInvocationCount        = 10;

            host.AddFunction("RECORD-STACK-DEPTH", (host, executionState, args) =>
            {
                var currentInterpreterStackDepth = executionState.StackFrame.Depth;
                var currentDotNetStackDepth      = new StackTrace().FrameCount;

                if (invocationCount++ > maxInvocationCount)
                {
                    throw new Exception($@"Executed more than {maxInvocationCount} times; probably not going to tailcall.
Last/current interpreter stack depth = {lastInterpreterStackDepth}/{currentInterpreterStackDepth}.
Last/current .NET stack depth = {lastDotNetStackDepth}/{currentDotNetStackDepth}");
                }

                if (currentInterpreterStackDepth == lastInterpreterStackDepth &&
                    currentDotNetStackDepth == lastDotNetStackDepth)
                {
                    // done
                    return(host.T);
                }
                else
                {
                    // haven't reached a stable stack depth; keep going
                    lastInterpreterStackDepth = currentInterpreterStackDepth;
                    lastDotNetStackDepth      = currentDotNetStackDepth;
                    return(host.Nil);
                }
            });
            var result = host.Eval(@"
(defun do-lots-of-tail-calls-with-if ()
    (if (record-stack-depth)
        t                                   ; done
        (do-lots-of-tail-calls-with-if)))   ; keep going
(do-lots-of-tail-calls-with-if)
").LastResult;

            Assert.True(invocationCount >= 2, $"Must have been invoked at least twice, but was only invoked {invocationCount} time(s).");
            Assert.Equal(host.T, result);
        }
Exemplo n.º 4
0
        public void HaltExecutionOnExpressionEvaluation()
        {
            var  host          = new LispHost();
            bool hitBreakpoint = false;
            bool sentinelHit   = false;

            host.AddFunction("SENTINEL", (host, executionState, args) =>
            {
                sentinelHit = true;
                return(new LispInteger(54));
            });
            host.RootFrame.EvaluatingExpression += (s, e) =>
            {
                if (!hitBreakpoint &&
                    e.Expression is LispList list &&
                    list.Value is LispSymbol symbol &&
                    symbol.LocalName == "+")
                {
                    hitBreakpoint   = true;
                    e.HaltExecution = true;
                }
            };
            var evalResult = host.Eval(@"
(defun inner-function ()
    (+ 40 2))
(defun outer-function ()
    (inner-function)
    (sentinel))
(outer-function)
");

            Assert.True(hitBreakpoint);
            Assert.False(evalResult.ExecutionState.IsExecutionComplete);
            Assert.Null(evalResult.LastResult);
            Assert.False(sentinelHit);
            host.EvalContinue(evalResult.ExecutionState);
            Assert.True(evalResult.ExecutionState.IsExecutionComplete);
            Assert.Equal(54, ((LispInteger)evalResult.LastResult).Value);
            Assert.True(sentinelHit);
        }
Exemplo n.º 5
0
        public void HaltExecutionOnFunctionReturn()
        {
            var  host        = new LispHost();
            bool sentinelHit = false;

            host.AddFunction("SENTINEL", (host, executionState, args) =>
            {
                sentinelHit = true;
                return(new LispInteger(54));
            });
            LispObject capturedReturnValue = null;

            host.RootFrame.FunctionReturned += (s, e) =>
            {
                if (e.Frame.FunctionSymbol.Value == "COMMON-LISP-USER:INNER-FUNCTION")
                {
                    e.HaltExecution     = true;
                    capturedReturnValue = e.ReturnValue;
                }
            };
            var evalResult = host.Eval(@"
(defun inner-function ()
    42)
(defun outer-function ()
    (inner-function)
    (sentinel))
(outer-function)
");

            Assert.False(evalResult.ExecutionState.IsExecutionComplete);
            Assert.Equal(42, ((LispInteger)capturedReturnValue).Value);
            Assert.Equal(42, ((LispInteger)evalResult.LastResult).Value);
            Assert.False(sentinelHit);
            host.EvalContinue(evalResult.ExecutionState);
            Assert.True(evalResult.ExecutionState.IsExecutionComplete);
            Assert.Equal(54, ((LispInteger)evalResult.LastResult).Value);
            Assert.True(sentinelHit);
        }
Exemplo n.º 6
0
        public void ExecutionCanStepIn(bool useTailCalls)
        {
            var host = new LispHost(useTailCalls: useTailCalls);

            host.AddFunction("NATIVE-FUNCTION", (host, executionState, args) =>
            {
                return(host.T);
            });
            var hasHalted = false;

            host.RootFrame.EvaluatingExpression += (s, e) =>
            {
                if (!hasHalted && e.Expression.ToString() == "(TEST-METHOD)")
                {
                    e.HaltExecution = true;
                    hasHalted       = true;
                }
            };
            var evalResult = host.Eval(@"
(defun test-method ()
    (native-function)
    (+ 1 1))
(test-method) ; initial halt here
");

            Assert.False(evalResult.ExecutionState.IsExecutionComplete);
            Assert.Equal("s: (TEST-METHOD)", evalResult.ExecutionState.PeekOperation().ToString());

            host.StepIn(evalResult.ExecutionState);
            Assert.False(evalResult.ExecutionState.IsExecutionComplete);
            Assert.Equal("s: (NATIVE-FUNCTION)", evalResult.ExecutionState.PeekOperation().ToString());

            host.StepIn(evalResult.ExecutionState); // can't step in to a native function; this is really a step over
            Assert.False(evalResult.ExecutionState.IsExecutionComplete);
            Assert.Equal("s: (+ 1 1)", evalResult.ExecutionState.PeekOperation().ToString());
        }