def equal(op1, op2): if is_iterable(op1) and is_iterable( op2): # list and vector are equal in tests =( if count(op1) != count(op2): return False return all(equal(el1, el2) for (el1, el2) in zip(op1, op2)) if is_hashmap(op1) and is_hashmap(op2): if set(keys(op1)) != set(keys(op2)): return False return all(equal(op1[key], op2[key]) for key in keys(op1)) return type(op1) == type(op2) and op1 == op2
def eval_ast(ast, env): if is_vector(ast): return make_vector(EVAL(elem, env) for elem in ast) if is_hashmap(ast): return make_hashmap_from_pydict( {key: EVAL(value, env) for key, value in items(ast)} ) if is_symbol(ast): return env.get(ast) elif is_list(ast): return make_list(EVAL(elem, env) for elem in ast) else: return ast
def quasiquote(ast): if is_list(ast): if is_empty(ast): return ast if ast[0] == make_symbol('unquote'): return ast[1] else: processed = [] for elt in ast[::-1]: if is_list(elt) and not is_empty(elt) and elt[0] == make_symbol('splice-unquote'): processed = make_list([make_symbol('concat'), elt[1], processed]) else: processed = make_list([make_symbol('cons'), quasiquote(elt), processed]) return make_list(processed) elif is_vector(ast): return make_list([make_symbol('vec'), *ast]) elif is_symbol(ast) or is_hashmap(ast): return make_list([make_symbol('quote'), ast]) return ast
def pr_str(entity, print_readably=True): if isinstance(entity, MalException): return f'{pr_str(entity.value)}' if isinstance(entity, Exception): return entity.args[0] elif is_function(entity): return '#function' elif is_nil(entity): return 'nil' elif is_bool(entity): return { TRUE: 'true', FALSE: 'false', }[entity] elif is_number(entity): return str(entity) elif is_symbol(entity): return str(entity, 'utf-8') elif is_keyword(entity): return ':' + entity[1:] elif is_string(entity): if print_readably: return '"' + entity.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n') + '"' return entity elif is_atom(entity): return f'(atom {deref(entity)})' elif is_list(entity): return '(' + ' '.join(pr_str(inner, print_readably) for inner in entity) + ')' elif is_vector(entity): return '[' + ' '.join(pr_str(inner, print_readably) for inner in entity) + ']' elif is_hashmap(entity): return ( '{' + ' '.join(f'{pr_str(k, print_readably)} {pr_str(v, print_readably)}' for k, v in entity.items()) + '}' ) raise RuntimeError(f'pr_str: unknown type {type(entity)}')