def ast_value(val, scope, return_name=False):
    '''Recursively parse out an AST value.  This makes no attempt to load
    modules or reconstruct functions on purpose.  We do not want to
    inadvertently call destructive code.
    '''
    # :TODO: refactor the hell out of this
    try:
        if isinstance(val, (ast.Assign, ast.Delete)):
            if hasattr(val, 'value'):
                value = ast_value(val.value, scope)
            else:
                value = None
            for t in val.targets:
                name = ast_value(t, scope, return_name=True)
                if isinstance(t.ctx, ast.Del):
                    if name in scope:
                        scope.pop(name)
                elif isinstance(t.ctx, ast.Store):
                    scope[name] = value
            return
        elif isinstance(val, ast.Expr) and isinstance(val.value, ast.Name):
            return ast_value(val.value)

        if isinstance(val, ast.Name):
            if isinstance(val.ctx, ast.Load):
                if val.id == 'None':
                    return None
                elif val.id == 'True':
                    return True
                elif val.id == 'False':
                    return False

                if val.id in scope:
                    return scope[val.id]

                if return_name:
                    return val.id
            elif isinstance(val.ctx, ast.Store):
                if return_name:
                    return val.id
            return None

        if isinstance(val, ast.Subscript):
            toslice = ast_value(val.value, scope)
            theslice = ast_value(val.slice, scope)
            return toslice[theslice]
        elif isinstance(val, ast.Index):
            return ast_value(val.value, scope)
        elif isinstance(val, ast.Slice):
            lower = ast_value(val.lower)
            upper = ast_value(val.upper)
            step = ast_value(val.step)
            return slice(lower, upper, step)

        if isinstance(val, list):
            return [ast_value(x, scope) for x in val]
        elif isinstance(val, tuple):
            return tuple(ast_value(x, scope) for x in val)

        if isinstance(val, ast.Attribute):
            name = ast_value(val.value, scope, return_name=True)
            if isinstance(val.ctx, ast.Load):
                return '.'.join((name, val.attr))
            if return_name:
                return name
        elif isinstance(val, ast.keyword):
            return {val.arg: ast_value(val.value, scope)}
        elif isinstance(val, ast.List):
            return [ast_value(x, scope) for x in val.elts]
        elif isinstance(val, ast.Tuple):
            return tuple(ast_value(x, scope) for x in val.elts)
        elif isinstance(val, ast.Dict):
            return dict(zip([ast_value(x, scope) for x in val.keys],
                            [ast_value(x, scope) for x in val.values]))
        elif isinstance(val, ast.Num):
            return val.n
        elif isinstance(val, ast.Str):
            return val.s
        elif hasattr(ast, 'Bytes') and isinstance(val, ast.Bytes):
            return bytes(val.s)
    except Exception:
        # Don't care, just return None
        pass

    return None