Пример #1
0
 def test_error_handling(self):
     TestData = collections.namedtuple("TestData", ["source", "expected"])
     tests = [
         TestData("5 + true;", "type mismatch: INTEGER + BOOLEAN"),
         TestData("5 + true; 5;", "type mismatch: INTEGER + BOOLEAN"),
         TestData("-true", "unknown operator: -BOOLEAN"),
         TestData("true + false", "unknown operator: BOOLEAN + BOOLEAN"),
         TestData("5; true + false; 5;",
                  "unknown operator: BOOLEAN + BOOLEAN"),
         TestData(
             "if (10 > 1) { true + false }",
             "unknown operator: BOOLEAN + BOOLEAN",
         ),
         TestData(
             "if (true) { if (true) { true + false } }",
             "unknown operator: BOOLEAN + BOOLEAN",
         ),
         TestData('"foo" - "bar"', "unknown operator: STRING - STRING"),
         TestData("foobar", "identifier not found: foobar"),
         TestData(
             '{"name": "Monkey"}[fn(x){x}]',
             "unusable as hash key: FUNCTION",
         ),
     ]
     for test in tests:
         evaluated = monkey.eval_source(test.source)
         self.assertIsInstance(evaluated, monkey.ObjectError)
         self.assertEqual(evaluated.what, test.expected)
Пример #2
0
 def test_eval_hash(self):
     source = "\n".join([
         'let two = "two";',
         "{"
         '  "one": 10 - 9,'
         "  two: 1 + 1,"
         '  "thr" + "ee": 6 / 2,'
         "  4: 4,"
         "  true: 5,"
         "  false: 6,"
         "}",
     ])
     evaluated = monkey.eval_source(source)
     self.assertIsInstance(evaluated, monkey.ObjectHash)
     self.assertEqual(len(evaluated.pairs), 6)
     keys = list(evaluated.pairs.keys())
     vals = list(evaluated.pairs.values())
     self.assertEqual(keys[0], monkey.ObjectString("one"))
     self.assertEqual(vals[0], monkey.ObjectInteger(1))
     self.assertEqual(keys[1], monkey.ObjectString("two"))
     self.assertEqual(vals[1], monkey.ObjectInteger(2))
     self.assertEqual(keys[2], monkey.ObjectString("three"))
     self.assertEqual(vals[2], monkey.ObjectInteger(3))
     self.assertEqual(keys[3], monkey.ObjectInteger(4))
     self.assertEqual(vals[3], monkey.ObjectInteger(4))
     self.assertEqual(keys[4], monkey.ObjectBoolean(True))
     self.assertEqual(vals[4], monkey.ObjectInteger(5))
     self.assertEqual(keys[5], monkey.ObjectBoolean(False))
     self.assertEqual(vals[5], monkey.ObjectInteger(6))
Пример #3
0
 def test_eval_boolean(self):
     TestData = collections.namedtuple("TestData", ["source", "expected"])
     tests = [
         TestData("true", True),
         TestData("false", False),
         TestData("1 < 2", True),
         TestData("1 > 2", False),
         TestData("1 < 1", False),
         TestData("1 > 1", False),
         TestData("1 == 1", True),
         TestData("1 != 1", False),
         TestData("1 == 2", False),
         TestData("1 != 2", True),
         TestData("true == true", True),
         TestData("false == false", True),
         TestData("true == false", False),
         TestData("false == true", False),
         TestData("true != true", False),
         TestData("false != false", False),
         TestData("true != false", True),
         TestData("false != true", True),
         TestData("(1 < 2) == true", True),
         TestData("(1 < 2) == false", False),
         TestData("(1 > 2) == true", False),
         TestData("(1 > 2) == false", True),
     ]
     for test in tests:
         evaluated = monkey.eval_source(test.source)
         self.check_boolean(evaluated, test.expected)
Пример #4
0
 def test_eval_function(self):
     source = "fn(x, y) { x + y + 2; };"
     evaluated = monkey.eval_source(source)
     self.assertIsInstance(evaluated, monkey.ObjectFunction)
     self.assertEqual(len(evaluated.parameters), 2)
     self.assertEqual(str(evaluated.parameters[0]), "x")
     self.assertEqual(str(evaluated.parameters[1]), "y")
     self.assertEqual(str(evaluated.body), "{ ((x + y) + 2) }")
Пример #5
0
 def test_eval_array(self):
     source = "[1, 2 * 2, 3 + 3]"
     evaluated = monkey.eval_source(source)
     self.assertIsInstance(evaluated, monkey.ObjectArray)
     self.assertEqual(len(evaluated.elements), 3)
     self.check_integer(evaluated.elements[0], 1)
     self.check_integer(evaluated.elements[1], 4)
     self.check_integer(evaluated.elements[2], 6)
Пример #6
0
 def test_closures(self):
     source = "\n".join([
         "let adder = fn(x) {",
         "  fn(y) { x + y }",
         "}",
         "let addtwo = adder(2)",
         "addtwo(3)",
     ])
     evaluated = monkey.eval_source(source)
     self.check_integer(evaluated, 5)
Пример #7
0
 def test_let_statement(self):
     TestData = collections.namedtuple("TestData", ["source", "expected"])
     tests = [
         TestData("let a = 5; a;", 5),
         TestData("let a = 5 * 5; a;", 25),
         TestData("let a = 5; let b = a; b;", 5),
         TestData("let a = 5; let b = a; let c = a + b + 5; c;", 15),
     ]
     for test in tests:
         evaluated = monkey.eval_source(test.source)
         self.check_integer(evaluated, test.expected)
Пример #8
0
 def test_return_statement(self):
     TestData = collections.namedtuple("TestData", ["source", "expected"])
     tests = [
         TestData("return 10;", 10),
         TestData("return 10; 9", 10),
         TestData("return 2 * 5; 9", 10),
         TestData("9; return 2 * 5; 9", 10),
     ]
     for test in tests:
         evaluated = monkey.eval_source(test.source)
         self.check_integer(evaluated, test.expected)
Пример #9
0
 def test_prefix_bang(self):
     TestData = collections.namedtuple("TestData", ["source", "expected"])
     tests = [
         TestData("!true", False),
         TestData("!false", True),
         TestData("!5", False),
         TestData("!!true", True),
         TestData("!!false", False),
         TestData("!!5", True),
     ]
     for test in tests:
         evaluated = monkey.eval_source(test.source)
         self.check_boolean(evaluated, test.expected)
Пример #10
0
 def test_function_application(self):
     TestData = collections.namedtuple("TestData", ["source", "expected"])
     tests = [
         TestData("let identity = fn(x) { x;        }; identity(5);", 5),
         TestData("let identity = fn(x) { return x; }; identity(5);", 5),
         TestData("let double = fn(x) { x * 2; }; double(5);", 10),
         TestData("let add = fn(x, y) { x + y; }; add(3, 5);", 8),
         TestData("let add = fn(x, y) { x + y; }; add(1 + 3, add(5, 7));",
                  16),
         TestData("fn(x) { x; }(5);", 5),
     ]
     for test in tests:
         evaluated = monkey.eval_source(test.source)
         self.check_integer(evaluated, test.expected)
Пример #11
0
 def test_hash_index_expressions(self):
     TestData = collections.namedtuple("TestData", ["source", "expected"])
     tests = [
         TestData('{"foo": 5}["foo"]', 5),
         TestData('{"foo": 5}["bar"]', None),
         TestData('let key = "foo"; {"foo": 5}[key]', 5),
         TestData('{}["foo"]', None),
         TestData("{5: 5}[5]", 5),
         TestData("{true: 5}[true]", 5),
         TestData("{false: 5}[false]", 5),
     ]
     for test in tests:
         evaluated = monkey.eval_source(test.source)
         self.check_result(evaluated, test.expected)
Пример #12
0
 def test_if_expression(self):
     TestData = collections.namedtuple("TestData", ["source", "expected"])
     tests = [
         TestData("if (true) { 10 }", 10),
         TestData("if (false) { 10 }", None),
         TestData("if (1) { 10 }", 10),
         TestData("if (1 < 2) { 10 }", 10),
         TestData("if (1 > 2) { 10 }", None),
         TestData("if (1 < 2) { 10 } else { 20 }", 10),
         TestData("if (1 > 2) { 10 } else { 20 }", 20),
     ]
     for test in tests:
         evaluated = monkey.eval_source(test.source)
         self.check_result(evaluated, test.expected)
Пример #13
0
 def test_builtin_functions(self):
     TestData = collections.namedtuple("TestData", ["source", "expected"])
     tests = [
         TestData('len("")', 0),
         TestData('len("four")', 4),
         TestData('len("hello world")', 11),
         TestData("len(1)", "argument to `len` not supported, got INTEGER"),
         TestData('len("one", "two")',
                  "wrong number of arguments. got=2, want=1"),
         TestData("len([1, 2, 3])", 3),
         TestData("len([])", 0),
         TestData("first([1, 2, 3])", 1),
         TestData("first([])", None),
         TestData("first(1)",
                  "argument to `first` must be ARRAY, got INTEGER"),
         TestData("first(1, 2)",
                  "wrong number of arguments. got=2, want=1"),
         TestData("last([1, 2, 3])", 3),
         TestData("last([])", None),
         TestData("last(1)",
                  "argument to `last` must be ARRAY, got INTEGER"),
         TestData("last(1, 2)", "wrong number of arguments. got=2, want=1"),
         TestData("rest([1, 2, 3])", [2, 3]),
         TestData("rest([])", None),
         TestData("rest(1)",
                  "argument to `rest` must be ARRAY, got INTEGER"),
         TestData("rest(1, 2)", "wrong number of arguments. got=2, want=1"),
         TestData("push([], 1)", [1]),
         TestData("push([1], 2)", [1, 2]),
         TestData("push(1, 2)",
                  "argument to `push` must be ARRAY, got INTEGER"),
         TestData("push(1)", "wrong number of arguments. got=1, want=2"),
     ]
     for test in tests:
         # TODO: These branches are a disorganized mess and could use some
         # cleanup.
         evaluated = monkey.eval_source(test.source)
         if isinstance(evaluated, monkey.ObjectInteger):
             self.check_integer(evaluated, test.expected)
         elif isinstance(evaluated, monkey.ObjectError):
             self.assertEqual(str(evaluated), test.expected)
         elif isinstance(evaluated, monkey.ObjectNull):
             self.assertEqual(test.expected, None)
         elif isinstance(evaluated, monkey.ObjectArray):
             for i in range(len(evaluated.elements)):
                 self.check_integer(evaluated.elements[i], test.expected[i])
         else:
             self.fail(f"Invalid type {type(evaluated)}")
Пример #14
0
 def test_array_index_expressions(self):
     TestData = collections.namedtuple("TestData", ["source", "expected"])
     tests = [
         TestData("[1, 2, 3][0]", 1),
         TestData("[1, 2, 3][1]", 2),
         TestData("[1, 2, 3][2]", 3),
         TestData("let i = 0; [1][i];", 1),
         TestData("[1, 2, 3][1 + 1];", 3),
         TestData("let myarray = [1, 2, 3]; myarray[2];", 3),
         TestData(
             ("let myarray = [1, 2, 3];\n"
              "myarray[0] + myarray[1] + myarray[2];"),
             6,
         ),
         TestData(
             "let myarray = [1, 2, 3]; let i = myarray[0]; myarray[i];", 2),
         TestData("[1, 2, 3][3]", None),
         TestData("[1, 2, 3][-1]", None),
     ]
     for test in tests:
         evaluated = monkey.eval_source(test.source)
         self.check_result(evaluated, test.expected)
Пример #15
0
 def test_eval_integer(self):
     TestData = collections.namedtuple("TestData", ["source", "expected"])
     tests = [
         TestData("5", 5),
         TestData("10", 10),
         TestData("-5", -5),
         TestData("-10", -10),
         TestData("5 + 5 + 5 + 5 - 10", 10),
         TestData("2 * 2 * 2 * 2 * 2", 32),
         TestData("-50 + 100 - 50", 0),
         TestData("5 * 2 + 10", 20),
         TestData("5 + 2 * 10", 25),
         TestData("20 + 2 * -10", 0),
         TestData("50 / 2 * 2 + 10", 60),
         TestData("2 * (5 + 10)", 30),
         TestData("3 * 3 * 3 + 10", 37),
         TestData("3 * (3 * 3) + 10", 37),
         TestData("(5 + 10 * 2 + 15 / 3) * 2 + -10", 50),
     ]
     for test in tests:
         evaluated = monkey.eval_source(test.source)
         self.check_integer(evaluated, test.expected)
Пример #16
0
 def test_eval_string(self):
     TestData = collections.namedtuple("TestData", ["source", "expected"])
     tests = [TestData('"foo"', "foo"), TestData('"foo bar"', "foo bar")]
     for test in tests:
         evaluated = monkey.eval_source(test.source)
         self.check_string(evaluated, test.expected)