public void SingleItem() { var host = new LispHost(); Assert.Equal(new LispInteger(3), host.Eval("3").LastResult); Assert.Equal(new LispFloat(3.0), host.Eval("3.0").LastResult); Assert.Equal(new LispString("a"), host.Eval("\"a\"").LastResult); }
public void Quoted() { var host = new LispHost(); Assert.Equal(LispSymbol.CreateFromString("A"), host.Eval("'a").LastResult); Assert.Equal(LispList.FromItems(new LispUnresolvedSymbol("QUOTE"), LispSymbol.CreateFromString("A")), host.Eval("''a").LastResult); Assert.Equal(LispList.FromItems(new LispInteger(1)), host.Eval("'(1)").LastResult); Assert.Equal("(QUOTE A)", host.Eval("(eval '''a)").LastResult.ToString()); }
public void MixedNumericFolding() { var host = new LispHost(); Assert.Equal(new LispFloat(10.0), host.Eval("(+ 1.0 2 3 4)").LastResult); Assert.Equal(new LispFloat(10.0), host.Eval("(+ 1 2.0 3 4)").LastResult); Assert.Equal(new LispRatio(5, 4), host.Eval("(+ (/ 1 4) 1)").LastResult); Assert.Equal(new LispRatio(5, 4), host.Eval("(+ 1 (/ 1 4))").LastResult); }
public void IntegerNumericFolding() { var host = new LispHost(); Assert.Equal(new LispInteger(-4), host.Eval("(- 4)").LastResult); Assert.Equal(new LispInteger(10), host.Eval("(+ 1 2 3 4)").LastResult); Assert.Equal(new LispInteger(1), host.Eval("(- 10 4 3 2)").LastResult); Assert.Equal(new LispInteger(24), host.Eval("(* 1 2 3 4)").LastResult); Assert.Equal(new LispInteger(4), host.Eval("(/ 24 3 2)").LastResult); }
public void FloatNumericFolding() { var host = new LispHost(); Assert.Equal(new LispFloat(-4.0), host.Eval("(- 4.0)").LastResult); Assert.Equal(new LispFloat(10.0), host.Eval("(+ 1.0 2.0 3.0 4.0)").LastResult); Assert.Equal(new LispFloat(1.0), host.Eval("(- 10.0 4.0 3.0 2.0)").LastResult); Assert.Equal(new LispFloat(24.0), host.Eval("(* 1.0 2.0 3.0 4.0)").LastResult); Assert.Equal(new LispFloat(4.0), host.Eval("(/ 24.0 3.0 2.0)").LastResult); }
public void EnterAndReturnFunctionEvent() { var host = new LispHost(); var sb = new StringBuilder(); host.Eval(@" (defun half (n) (* n 0.5)) (defun average (x y) (+ (half x) (half y))) "); host.RootFrame.FunctionEntered += (sender, e) => sb.AppendLine($"entered {e.Frame.FunctionSymbol.ToDisplayString(host.CurrentPackage)}"); host.RootFrame.FunctionReturned += (sender, e) => sb.AppendLine($"returned from {e.Function.NameSymbol.ToDisplayString(host.CurrentPackage)} with {e.ReturnValue}"); host.Eval("(average 3 7)"); var actual = NormalizeNewlines(sb.ToString().Trim()); var expected = NormalizeNewlines(@" entered AVERAGE entered HALF entered * entered CONS returned from CONS with (1 3 0.5) entered REDUCE entered KERNEL:*/2 returned from KERNEL:*/2 with 3 entered KERNEL:*/2 returned from KERNEL:*/2 with 1.5 returned from REDUCE with 1.5 returned from * with 1.5 returned from HALF with 1.5 entered HALF entered * entered CONS returned from CONS with (1 7 0.5) entered REDUCE entered KERNEL:*/2 returned from KERNEL:*/2 with 7 entered KERNEL:*/2 returned from KERNEL:*/2 with 3.5 returned from REDUCE with 3.5 returned from * with 3.5 returned from HALF with 3.5 entered + entered CONS returned from CONS with (0 1.5 3.5) entered REDUCE entered KERNEL:+/2 returned from KERNEL:+/2 with 1.5 entered KERNEL:+/2 returned from KERNEL:+/2 with 5 returned from REDUCE with 5 returned from + with 5 returned from AVERAGE with 5 ".Trim()); Assert.Equal(expected, actual); }
public void LambdaCapture() { var host = new LispHost(); host.Eval(@" (defun make-greater-p (n) #'(lambda (x) (> x n))) (setf pred (make-greater-p 3)) "); Assert.Equal(host.Nil, host.Eval("(funcall pred 2)").LastResult); Assert.Equal(host.T, host.Eval("(funcall pred 5)").LastResult); Assert.Equal(new LispInteger(4), host.Eval("(find-if pred '(2 3 4 5 6 7 8 9))").LastResult); }
public void ExecutionCanBeHaltedWhenAnErrorIsExplicitlyRaised() { var host = new LispHost(); LispError capturedError = null; host.RootFrame.ErrorOccured += (s, e) => { capturedError = e.Error; }; var evalResult = host.Eval(@" (defun test-method () (error ""test error"")) (test-method) "); // errors _always_ halt execution Assert.False(evalResult.ExecutionState.IsExecutionComplete); Assert.Equal("test error", ((LispError)evalResult.LastResult).Message); Assert.Equal("test error", capturedError.Message); Assert.True(ReferenceEquals(capturedError, evalResult.LastResult)); // all future processing stops host.EvalContinue(evalResult.ExecutionState); Assert.False(evalResult.ExecutionState.IsExecutionComplete); }
public void HaltExecutionOnEvaluatingFunctionArgument() { var host = new LispHost(); var hitBreakpoint = false; host.RootFrame.EvaluatingExpression += (s, e) => { if (!hitBreakpoint && e.Expression is LispList list && list.ToString() == "(* 2 2)") { hitBreakpoint = true; e.HaltExecution = true; } }; var evalResult = host.Eval(@" (+ (* 2 2) (* 3 3)) "); Assert.True(hitBreakpoint); Assert.False(evalResult.ExecutionState.IsExecutionComplete); Assert.Null(evalResult.LastResult); host.EvalContinue(evalResult.ExecutionState); Assert.True(evalResult.ExecutionState.IsExecutionComplete); Assert.Equal(13, ((LispInteger)evalResult.LastResult).Value); }
public void ExecutionCannotBeHaltedWhenEvaluatingFromWithinANativeMacro() { var host = new LispHost(); host.AddMacro("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); }
public void ExecutionStepInWhenNextOperationIsNotAnExpression() { var host = new LispHost(); host.RootFrame.FunctionReturned += (s, e) => { if (e.Frame.FunctionSymbol.Value == "COMMON-LISP-USER:TEST-METHOD") { e.HaltExecution = true; } }; var evalResult = host.Eval(@" (defun test-method () (+ 1 2)) (test-method) (+ 4 5) "); Assert.False(evalResult.ExecutionState.IsExecutionComplete); Assert.Equal(3, ((LispInteger)evalResult.LastResult).Value); Assert.Null(evalResult.ExecutionState.PeekCurrentExpression()); host.StepIn(evalResult.ExecutionState); // nothing to step in to, so it's really step out _then_ step in Assert.False(evalResult.ExecutionState.IsExecutionComplete); Assert.Equal("s: 4", evalResult.ExecutionState.PeekOperation().ToString()); host.EvalContinue(evalResult.ExecutionState); Assert.True(evalResult.ExecutionState.IsExecutionComplete); Assert.Equal(9, ((LispInteger)evalResult.LastResult).Value);; }
public void KeywordSymbolsImmediatelyResolveToThemselves() { var host = new LispHost(useInitScript: false); var result = host.Eval(":some-keyword"); Assert.Equal(new LispResolvedSymbol("KEYWORD", "SOME-KEYWORD", isPublic: true), result.LastResult); }
public void PackagesCanInheritSymbols() { var host = new LispHost(useInitScript: false); var result = host.Eval(@" (defpackage :a) (in-package :a) (setf aa 1) (defpackage :b (:use :a)) (in-package :b) (setf bb 2) (defpackage :x) (in-package :x) (setf xx 3) (defpackage :c (:use :b :x)) (in-package :c) (list aa ; a:aa => 1 bb ; b:bb => 2 xx) ; x:xx => 3 "); Assert.Equal("(1 2 3)", result.LastResult.ToString()); }
public void ExecutionStepOutWhenNextOperationIsNotAnExpression() { var host = new LispHost(); host.RootFrame.FunctionReturned += (s, e) => { if (e.Frame.FunctionSymbol.Value == "COMMON-LISP-USER:TEST-METHOD") { e.HaltExecution = true; } }; var evalResult = host.Eval(@" (defun test-method () (+ 1 2)) (test-method) (+ 4 5) "); Assert.False(evalResult.ExecutionState.IsExecutionComplete); Assert.Equal(3, ((LispInteger)evalResult.LastResult).Value); Assert.Null(evalResult.ExecutionState.PeekCurrentExpression()); host.StepOut(evalResult.ExecutionState); // stepping out here steps out of everything Assert.True(evalResult.ExecutionState.IsExecutionComplete); Assert.Equal(9, ((LispInteger)evalResult.LastResult).Value);; }
public void ExecutionCanStepOut(bool useTailCalls) { var host = new LispHost(useTailCalls: useTailCalls); var hasHalted = false; host.RootFrame.EvaluatingExpression += (s, e) => { if (!hasHalted && e.Expression.ToString() == "(+ 1 1)") { e.HaltExecution = true; hasHalted = true; } }; var evalResult = host.Eval(@" (defun test-method () (+ 1 1) ; initial halt here (+ 2 2)) (test-method) (+ 3 3) (+ 4 4) "); Assert.False(evalResult.ExecutionState.IsExecutionComplete); Assert.Equal("s: (+ 1 1)", evalResult.ExecutionState.PeekOperation().ToString()); host.StepOut(evalResult.ExecutionState); Assert.False(evalResult.ExecutionState.IsExecutionComplete); Assert.Equal("s: (+ 3 3)", evalResult.ExecutionState.PeekOperation().ToString()); host.StepOut(evalResult.ExecutionState); // can't step out at the root level; this was really a run to end Assert.True(evalResult.ExecutionState.IsExecutionComplete); Assert.Equal(8, ((LispInteger)evalResult.LastResult).Value); }
public void HaltExecutionOnMacroExpansion() { var host = new LispHost(); host.AddMacro("FOURTY-TWO", (host, executionState, args) => { return(new LispInteger(42)); }); host.RootFrame.MacroExpanded += (s, e) => { if (e.Macro.NameSymbol.LocalName == "FOURTY-TWO") { e.HaltExecution = true; } }; var evalResult = host.Eval(@" (fourty-two) (+ 1 2) "); Assert.False(evalResult.ExecutionState.IsExecutionComplete); Assert.Equal("s: 42", evalResult.ExecutionState.PeekOperation().ToString()); host.EvalContinue(evalResult.ExecutionState); Assert.True(evalResult.ExecutionState.IsExecutionComplete); Assert.Equal(3, ((LispInteger)evalResult.LastResult).Value); }
public void HaltExecutionOnFunctionEnter() { var host = new LispHost(); host.RootFrame.FunctionEntered += (s, e) => { if (e.Frame.FunctionSymbol.Value == "COMMON-LISP-USER:INNER-FUNCTION") { e.HaltExecution = true; } }; var evalResult = host.Eval(@" (defun inner-function () 42) (defun outer-function () (inner-function)) (outer-function) "); Assert.False(evalResult.ExecutionState.IsExecutionComplete); Assert.Null(evalResult.LastResult); host.EvalContinue(evalResult.ExecutionState); Assert.True(evalResult.ExecutionState.IsExecutionComplete); Assert.Equal(42, ((LispInteger)evalResult.LastResult).Value); }
public void ErrorStackPropagationFromInitScript() { var host = new LispHost(); var evalResult = host.Eval("*REPL*", "(+ 1 \"two\" 3)"); var error = (LispError)evalResult.LastResult; var errorStackFrame = error.StackFrame; Assert.Equal("KERNEL:+/2", errorStackFrame.FunctionSymbol.Value); Assert.Null(errorStackFrame.SourceLocation); // in native code Assert.Equal("REDUCE", errorStackFrame.Parent.FunctionSymbol.LocalName); Assert.Null(errorStackFrame.Parent.SourceLocation); // in native code // this function can move around, but the body is one line below the definition var plusFunction = host.GetValue <LispFunction>("+"); var plusFunctionLocation = plusFunction.SourceLocation.Value; Assert.Equal("+", errorStackFrame.Parent.Parent.FunctionSymbol.LocalName); Assert.Equal(new LispSourceLocation("init.lisp", new LispSourcePosition(plusFunctionLocation.Start.Line + 1, 34), new LispSourcePosition(plusFunctionLocation.Start.Line + 1, 40)), errorStackFrame.Parent.Parent.SourceLocation); Assert.Equal("(ROOT)", errorStackFrame.Parent.Parent.Parent.FunctionSymbol.LocalName); Assert.Equal(new LispSourceLocation("*REPL*", new LispSourcePosition(1, 12), new LispSourcePosition(1, 13)), errorStackFrame.Parent.Parent.Parent.SourceLocation); // TODO: [(1, 6)-(1, 11)) is better since that argument isn't a number Assert.Null(errorStackFrame.Parent.Parent.Parent.Parent); }
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); }
public void ExecutionCanBeHaltedWhenAnErrorIsNaturallyEncountered() { var host = new LispHost(); LispError capturedError = null; host.RootFrame.ErrorOccured += (s, e) => { capturedError = e.Error; }; var evalResult = host.Eval(@" (defun test-method () (not-a-method)) (test-method) "); // errors _always_ halt execution Assert.False(evalResult.ExecutionState.IsExecutionComplete); Assert.Equal("Undefined macro/function 'NOT-A-METHOD', found '<null>'", ((LispError)evalResult.LastResult).Message); Assert.Equal("Undefined macro/function 'NOT-A-METHOD', found '<null>'", capturedError.Message); Assert.True(ReferenceEquals(capturedError, evalResult.LastResult)); // all future processing stops host.EvalContinue(evalResult.ExecutionState); Assert.False(evalResult.ExecutionState.IsExecutionComplete); }
public void DotNotationLists() { var host = new LispHost(); var result = host.Eval("'(a . (b . (c)))").LastResult; var actual = result.ToString(); Assert.Equal("(A B C)", actual); }
public void InvokeBuiltInNamedFunctionReference() { var host = new LispHost(); var result = host.Eval(@"(funcall #'cons 'a 'b)").LastResult; var expected = LispList.FromItemsImproper(LispSymbol.CreateFromString("A"), LispSymbol.CreateFromString("B")); Assert.Equal(expected, result); }
private void EvalFile(string fileName) { var contents = GetFileContents(fileName); var host = new LispHost(); var result = host.Eval(contents); Assert.True(result.LastResult.Equals(host.T), result.LastResult.ToString()); }
public void SourceLocationIsNotPropagatedFromComputedValues2() { var host = new LispHost("host.lisp"); var result = host.Eval("some-other-location.lisp", "(+ 1 2)").LastResult; Assert.Equal(3, ((LispInteger)result).Value); Assert.Null(result.SourceLocation); }
public void PackageIsCreatedWithDefPackageWithString() { var host = new LispHost(); host.Eval("(defpackage \"TEST-PACKAGE\") (in-package :test-package)"); var package = host.GetValue <LispPackage>("*PACKAGE*"); Assert.Equal("TEST-PACKAGE", package.Name); }
public void InvokeLambdaFromReference() { var host = new LispHost(); var result = host.Eval(@" (funcall #'(lambda (n) (+ 1 n)) 2) ").LastResult; Assert.Equal(new LispInteger(3), result); }
public void ApplyFunctionReference() { var host = new LispHost(); var result = host.Eval(@" (apply #'+ '(2 3)) ").LastResult; Assert.Equal(5, ((LispInteger)result).Value); }
public void ErrorGeneration() { var host = new LispHost(); var result = host.Eval(@" (error ""Expected '~s' but got '~s'"" 1 2) ").LastResult; Assert.Equal("Expected '1' but got '2'", ((LispError)result).Message); }
public void PackageIsCreatedWithDefPackageWithKeyword() { var host = new LispHost(useInitScript: false); host.Eval("(defpackage :test-package) (in-package :test-package)"); var package = host.GetValue <LispPackage>("*PACKAGE*"); Assert.Equal("TEST-PACKAGE", package.Name); }
public void FormatOutputWithArgument() { var output = new StringWriter(); var host = new LispHost(output: output); host.Eval(@"(format t ""hello ~S"" ""world"")"); var result = NormalizeNewlines(output.ToString()); Assert.Equal("hello \"world\"", result); }