def _test_pattern(self, pattern_code, target_code, expected_scope, initial_scope=None): if initial_scope is None: initial_scope = {} scope = Scope(initial_scope, root) pattern = isheval(pattern_code) self.assertTrue(pattern.match(isheval(target_code), scope)) self.assertEqual(scope.identifiers(), expected_scope.keys()) for key in expected_scope: self.assertEqual(expected_scope[key], scope.get(key))
def test_function_patterns(self): unary_compose = isheval(''' (fn [fn1 fn2] (fn [arg] (fn1 (fn2 arg)) ) )''') self.assertEqual(Function, type(unary_compose)) scope = Scope({'unary_compose': unary_compose}, root) cadr = isheval('(unary_compose car cdr)', scope) scope.set('cadr', cadr) self.assertEqual(2, isheval('(cadr [1 2 3])', scope)) self.assertEqual(3, isheval('((unary_compose cadr cdr) [1 2 3])', scope))
def test_curry_only_evaluates_arguments_once(self): count = 0 def increment_count(args, scope): nonlocal count count += 1 return 5 scope = Scope({'inc': increment_count}, root) self.assertEqual(0, count) curried = isheval('(curry list (inc))', scope) self.assertEqual(1, count) scope.set('curried', curried) self.assertEqual(Pair(5, Pair(10, Pair(20, nil))), isheval('(curried 10 20)', scope)) self.assertEqual(1, count)
def test_function_patterns_simple(self): compose = isheval('(fn [fn1 fn2] (fn [y] (fn2 (fn1 y))))') scope = Scope({'compose': compose}, root) self.assertEqual(10, isheval('((compose id id) 10)', scope)) my_car = isheval('(fn [x:xs] x)') scope = Scope({'my-car': my_car}, root) self.assertEqual(3, isheval('(my-car [3 4 5])', scope)) my_id = isheval('(fn x x)') scope = Scope({'my-id': my_id}, root) self.assertEqual(20, isheval('(my-id | 20)', scope)) first_arg = isheval('(fn x:xs x)') scope = Scope({'first-arg': first_arg}, root) self.assertEqual(6, isheval('(first-arg 6 7 8)', scope))
def match(arg, scope): assert type(arg) is Pair assert type(arg.cdr) is Pair assert eval_node(arg.cdr.cdr, scope) is nil pattern = eval_node(arg.car, scope) target = eval_node(arg.cdr.car, scope) new_scope = Scope({}, scope) return pattern.match(target, new_scope)
def test_eval_nested_functions(self): compose = isheval('(fn x (fn y ((car (cdr x)) ((car x) (car y)))))') self.assertEqual(Function, type(compose)) scope = Scope({'compose': compose}, root) self.assertEqual(compose, isheval('compose', scope)) self.assertEqual(10, isheval('((compose id id) 10)', scope)) self.assertEqual(Pair(10, nil), isheval('((compose id id) [10])', scope))
def _test_pattern_fails(self, pattern_code, target_code, initial_scope=None): if initial_scope is None: initial_scope = {} scope = Scope(initial_scope, root) self.assertFalse( isheval(pattern_code).match(isheval(target_code), scope))
def test_eval_functions_in_scope(self): my_id = isheval('(fn x x)') scope = Scope({'my_id': my_id}, root) self.assertEqual(my_id, isheval('my_id', scope)) self.assertEqual(my_id, isheval('(my_id | (my_id | my_id))', scope)) self.assertEqual(3, isheval('(my_id | 3)', scope)) self.assertEqual(Pair(my_id, nil), isheval('(my_id my_id)', scope)) self.assertEqual(my_id, isheval('(my_id | my_id)', scope)) self.assertEqual(Pair(20, nil), isheval('(my_id 20)', scope))
def test_scope(self): parent = Scope({}, None) parent.set('foo', 10) parent.set('bar', 20) child = Scope({}, parent) child.set('foo', 15) self.assertTrue(child.set_recursive('bar', 25)) self.assertEqual(10, parent.get('foo')) self.assertEqual(25, parent.get('bar')) self.assertEqual(15, child.get('foo')) self.assertEqual(25, parent.get('bar')) self.assertRaises(Exception, child.get, 'baz')