def validate(bo, error_level: str = "<STR_LIT>") -> Tuple[bool, List[Tuple[str, str]]]:
if bo.ast:<EOL><INDENT>bo = validate_functions(bo.ast, bo)  <EOL>if error_level == "<STR_LIT>":<EOL><INDENT>bo = validate_arg_values(bo.ast, bo)  <EOL><DEDENT><DEDENT>else:<EOL><INDENT>bo.validation_messages.append(("<STR_LIT>", "<STR_LIT>"))<EOL><DEDENT>for msg in bo.validation_messages:<EOL><INDENT>if msg[<NUM_LIT:0>] == "<STR_LIT>":<EOL><INDENT>bo.parse_valid = False<EOL>break<EOL><DEDENT><DEDENT>return bo<EOL>
Semantically validate BEL AST

    Add errors and warnings to bel_obj.validation_messages

    Error Levels are similar to log levels - selecting WARNING includes both
    WARNING and ERROR, selecting ERROR just includes ERROR

    Args:
        bo: main BEL language object
        error_level: return ERRORs only or also WARNINGs

    Returns:
        Tuple[bool, List[Tuple[str, str]]]: (is_valid, messages)