Parse the given target. If it is a file-like object, then parse its
    contents. If given a string, perform one of the following actions

     - If the string is a valid file path, then open and parse it
     - If the string is a valid directory path, then recursively look for
       files ending in .ly or .ily
     - Otherwise parse the string directly.

def parse(target, trace=False, **kwargs):
    """Parse the given target. If it is a file-like object, then parse its
    contents. If given a string, perform one of the following actions

     - If the string is a valid file path, then open and parse it
     - If the string is a valid directory path, then recursively look for
       files ending in .ly or .ily
     - Otherwise parse the string directly.

    """

    # Beware! This function, that actually is the core of all the
    # business, is written to minimize the responsibilities of each
    # chunk of code, keeping things simple. Performance may degrade
    # because of this, but without actual measurements the simplest
    # choice is the best one.

    if hasattr(target, 'read'):
        # It's a file-like object
        file_content = target.read()
        return parse(file_content, trace, **kwargs)

    if os.path.isfile(target):
        if target.endswith(".ily") or target.endswith(".ly"):
            console.display("Parsing", target)
            with io.open(target, "r", encoding="utf-8") as fp:
                return parse(fp, trace, filename=target, **kwargs)
        else:
            return []

    if os.path.isdir(target):
        docs = []
        logging.info("Parsing directory {}", target)
        for root, _, files in os.walk(target):
            for f in files:
                fname = os.path.join(root, f)
                file_docs = parse(fname, trace, **kwargs)
                docs.extend(file_docs)
        return docs

    # We were given a text, so parse it directly
    metrics = kwargs.get("metrics", None)
    if metrics is not None:
        metrics.record_file(target)

    docs = []
    parser = LilyParser(parseinfo=True)
    try:
        parser.parse(target,
                     'lilypond',
                     semantics=DocumentationSemantics(docs),
                     filename=kwargs.get("filename", None),
                     trace=trace)
    except FailedParse as err:
        logging.warn(err)
        if metrics is not None:
            metrics.record_error(err)
    except RuntimeError as err:
        logging.warn(err)
        if metrics is not None:
            metrics.record_error(err)

    return docs