vm_test.go 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. package vm
  2. import (
  3. "fmt"
  4. "github/runnignwater/monkey/ast"
  5. "github/runnignwater/monkey/compiler"
  6. "github/runnignwater/monkey/lexer"
  7. "github/runnignwater/monkey/object"
  8. "github/runnignwater/monkey/parser"
  9. "testing"
  10. )
  11. type vmTestCase struct {
  12. input string
  13. expected interface{}
  14. }
  15. func TestIntegerArithmetic(t *testing.T) {
  16. tests := []vmTestCase{
  17. {"1", 1},
  18. {"2", 2},
  19. {"1 + 2", 3},
  20. {"1 - 2", -1},
  21. {"1 * 2", 2},
  22. {"4 / 2", 2},
  23. {"50 / 2 * 2 + 10 - 5", 55},
  24. {"5 * (2 + 10)", 60},
  25. {"5 + 5 + 5 + 5 - 10", 10},
  26. {"2 * 2 * 2 * 2 * 2", 32},
  27. {"5 * 2 + 10", 20},
  28. {"5 + 2 * 10", 25},
  29. {"5 * (2 + 10)", 60},
  30. }
  31. runVmTests(t, tests)
  32. }
  33. func runVmTests(t *testing.T, tests []vmTestCase) {
  34. t.Helper()
  35. for _, tt := range tests {
  36. program := parse(tt.input)
  37. comp := compiler.New()
  38. err := comp.Compile(program)
  39. if err != nil {
  40. t.Fatalf("compler error: %s", err)
  41. }
  42. vm := New(comp.ByteCode())
  43. err = vm.Run()
  44. if err != nil {
  45. t.Fatalf("vm error: %s", err)
  46. }
  47. stackElem := vm.LastPopStackElem()
  48. testExpectedObject(t, tt.expected, stackElem)
  49. }
  50. }
  51. func parse(input string) *ast.Program {
  52. l := lexer.New(input)
  53. p := parser.New(l)
  54. return p.ParseProgram()
  55. }
  56. func testExpectedObject(
  57. t *testing.T,
  58. expected interface{},
  59. actual object.Object,
  60. ) {
  61. t.Helper()
  62. switch expected := expected.(type) {
  63. case int:
  64. err := testIntegerObject(int64(expected), actual)
  65. if err != nil {
  66. t.Errorf("testIntegerObject failed: %s", err)
  67. }
  68. }
  69. }
  70. func testIntegerObject(expected int64, actual object.Object) error {
  71. result, ok := actual.(*object.Integer)
  72. if !ok {
  73. return fmt.Errorf("object is not Integer. got=%T (%+v)", actual, actual)
  74. }
  75. if result.Value != expected {
  76. return fmt.Errorf("object has wrong value. got=%d, want=%d", result.Value, expected)
  77. }
  78. return nil
  79. }