def atomize(param) -> Atom: if re.search(r"^\d+\.\d+$", param): return Atom(float(param)) elif re.search(r"^\d+$", param): return Atom(int(param)) else: return Atom(param)
def test_list_recursion(list_env): parse_expression( "(define (sum lon) (if (empty? lon) 0 (+ (car lon) (sum (cdr lon)))))", list_env, ).eval(list_env) assert parse_expression("(sum 5to1)", list_env).eval(list_env) == Atom(15)
def parse(exp_list: Union[str, List]) -> Expression: def atomize(param) -> Atom: if re.search(r"^\d+\.\d+$", param): return Atom(float(param)) elif re.search(r"^\d+$", param): return Atom(int(param)) else: return Atom(param) if isinstance(exp_list, str): return atomize(exp_list) else: exp = exp_list.pop(0) if exp == "lambda": return Function(parse(exp_list[1]), env, *exp_list[0]) elif exp == "define": if isinstance(exp_list[0], str): return Definition(exp_list[0], parse(exp_list[1])) elif isinstance(exp_list[0], list): func_name = exp_list[0].pop(0) return Definition( func_name, Function(parse(exp_list[1]), env, *exp_list[0])) args = list(map(parse, exp_list)) if exp == "if": return If(*args) elif exp == "and": return And(*args) elif exp == "or": return Or(*args) elif exp == "cons": return Cons(*args) else: return FunctionCall(Atom(exp), *args)
def test_recursion(basic_env): parse_expression("(define (fact n) (if (zero? n) 1 (* n (fact (- n 1)))))", basic_env).eval(basic_env) assert parse_expression("(fact 5)", basic_env).eval(basic_env) == Atom(120)
def test_define_lambda(basic_env): parse_expression("(define sqr (lambda (x) (* x x)))", basic_env).eval(basic_env) assert parse_expression("(sqr 2)", basic_env).eval(basic_env) == Atom(4)
def test_builtin_math(basic_env): assert parse_expression("(+ 1 2)", basic_env).eval(basic_env) == Atom(3) assert parse_expression("(* 3 4)", basic_env).eval(basic_env) == Atom(12) assert parse_expression("(- 3 9)", basic_env).eval(basic_env) == Atom(-6) assert parse_expression("(/ 15 5)", basic_env).eval(basic_env) == Atom(3)
def add(*args: Atom) -> Atom: rsf = 0 for arg in args: rsf += arg.val return Atom(rsf)
def divide(*args: Atom) -> Atom: rsf = args[0].val for arg in args[1:]: rsf /= arg.val return Atom(rsf)
def multiply(*args: Atom) -> Atom: rsf = 1 for arg in args: rsf *= arg.val return Atom(rsf)
def subtract(*args: Atom) -> Atom: rsf = args[0].val for arg in args[1:]: rsf -= arg.val return Atom(rsf)