Event Stream

This example shows how to parse a WDL document into an event stream, printing that stream to the terminal.

sprocket_bio/examples/event_stream.py
import argparse
import pathlib
import sys

from sprocket_bio.diagnostics import Mode, emit_diagnostics
from sprocket_bio.grammar import Severity, SupportedVersion
from sprocket_bio.grammar.grammar import document
from sprocket_bio.grammar.parser import Event
from sprocket_bio.grammar.version import V1


def parse_args() -> argparse.Namespace:
    """Parses command-line arguments and returns them."""

    parser = argparse.ArgumentParser(
        description="Parses a WDL document and prints the event stream"
    )

    parser.add_argument(
        "source_file",
        type=pathlib.Path,
        help="path to WDL document",
        metavar="<source_file>",
    )

    return parser.parse_args()


def main() -> None:
    args = parse_args()

    with open(args.source_file, "rt", encoding="utf-8") as f:
        source = f.read()

    # Parse the source string into a list of parser events.
    events, diagnostics = document(
        source, fallback_version=SupportedVersion.V1(V1.ZERO)
    )

    # Emit diagnostics, if there are any.
    emit_diagnostics(
        str(args.source_file), source, diagnostics, report_mode=Mode.FULL, colorize=True
    )

    # If any of the diagnostics are errors, exit.
    if any([d.severity is Severity.ERROR for d in diagnostics]):
        sys.exit(1)

    # Get the byte representation of the source code.
    source_bytes = source.encode("utf-8")

    indent = 0

    # Print all events in the stream.
    for event in events:
        match event:
            case Event.NodeStarted(kind, _):
                print("  " * indent + str(kind))
                indent += 1
            case Event.NodeFinished():
                indent -= 1
            case Event.Token(kind, span):
                # Get the text in the source code represented by this span. We convert the string
                # to bytes first, as `Span`s index bytes instead of Unicode code points. Not doing
                # so will result in the wrong text being displayed.
                token_text = source_bytes[span.start : span.end].decode("utf-8")
                print("  " * indent + f"{kind}@{span} {token_text!r}")


if __name__ == "__main__":
    main()

If you have the Python bindings installed, you can run the example yourself:

$ python -m sprocket_bio.examples.event_stream example.wdl
SyntaxKind.ROOT_NODE
  SyntaxKind.VERSION_STATEMENT_NODE
    SyntaxKind.VERSION_KEYWORD@0..7 'version'
    SyntaxKind.WHITESPACE@7..8 ' '
    SyntaxKind.VERSION@8..11 '1.3'
  SyntaxKind.WHITESPACE@11..13 '\n\n'
  SyntaxKind.TASK_DEFINITION_NODE
    SyntaxKind.TASK_KEYWORD@13..17 'task'
    SyntaxKind.WHITESPACE@17..18 ' '
    SyntaxKind.IDENT@18..27 'say_hello'
    SyntaxKind.WHITESPACE@27..28 ' '
    SyntaxKind.OPEN_BRACE@28..29 '{'
    SyntaxKind.WHITESPACE@29..34 '\n    '
    SyntaxKind.INPUT_SECTION_NODE
      SyntaxKind.INPUT_KEYWORD@34..39 'input'
      SyntaxKind.WHITESPACE@39..40 ' '
      SyntaxKind.OPEN_BRACE@40..41 '{'
      SyntaxKind.WHITESPACE@41..50 '\n        '
      SyntaxKind.UNBOUND_DECL_NODE
        SyntaxKind.PRIMITIVE_TYPE_NODE
          SyntaxKind.STRING_TYPE_KEYWORD@50..56 'String'
        SyntaxKind.WHITESPACE@56..57 ' '
        SyntaxKind.IDENT@57..65 'greeting'
      SyntaxKind.WHITESPACE@65..70 '\n    '
      SyntaxKind.CLOSE_BRACE@70..71 '}'
    SyntaxKind.WHITESPACE@71..77 '\n\n    '
    SyntaxKind.COMMAND_SECTION_NODE
      SyntaxKind.COMMAND_KEYWORD@77..84 'command'
      SyntaxKind.WHITESPACE@84..85 ' '
      SyntaxKind.OPEN_HEREDOC@85..88 '<<<'
      SyntaxKind.LITERAL_COMMAND_TEXT@88..103 '\n        echo "'
      SyntaxKind.PLACEHOLDER_NODE
        SyntaxKind.PLACEHOLDER_OPEN@103..105 '~{'
        SyntaxKind.ABANDONED
          SyntaxKind.NAME_REF_EXPR_NODE
            SyntaxKind.IDENT@105..113 'greeting'
          SyntaxKind.CLOSE_BRACE@113..114 '}'
        SyntaxKind.LITERAL_COMMAND_TEXT@114..128 ', world!"\n    '
        SyntaxKind.CLOSE_HEREDOC@128..131 '>>>'
      SyntaxKind.WHITESPACE@131..137 '\n\n    '
      SyntaxKind.OUTPUT_SECTION_NODE
        SyntaxKind.OUTPUT_KEYWORD@137..143 'output'
        SyntaxKind.WHITESPACE@143..144 ' '
        SyntaxKind.OPEN_BRACE@144..145 '{'
        SyntaxKind.WHITESPACE@145..154 '\n        '
        SyntaxKind.BOUND_DECL_NODE
          SyntaxKind.PRIMITIVE_TYPE_NODE
            SyntaxKind.STRING_TYPE_KEYWORD@154..160 'String'
          SyntaxKind.WHITESPACE@160..161 ' '
          SyntaxKind.IDENT@161..164 'out'
          SyntaxKind.WHITESPACE@164..165 ' '
          SyntaxKind.ASSIGNMENT@165..166 '='
          SyntaxKind.WHITESPACE@166..167 ' '
          SyntaxKind.ABANDONED
            SyntaxKind.CALL_EXPR_NODE
              SyntaxKind.IDENT@167..178 'read_string'
              SyntaxKind.OPEN_PAREN@178..179 '('
              SyntaxKind.ABANDONED
                SyntaxKind.CALL_EXPR_NODE
                  SyntaxKind.IDENT@179..185 'stdout'
                  SyntaxKind.OPEN_PAREN@185..186 '('
                  SyntaxKind.CLOSE_PAREN@186..187 ')'
                SyntaxKind.CLOSE_PAREN@187..188 ')'
            SyntaxKind.WHITESPACE@188..193 '\n    '
            SyntaxKind.CLOSE_BRACE@193..194 '}'
          SyntaxKind.WHITESPACE@194..200 '\n\n    '
          SyntaxKind.REQUIREMENTS_SECTION_NODE
            SyntaxKind.REQUIREMENTS_KEYWORD@200..212 'requirements'
            SyntaxKind.WHITESPACE@212..213 ' '
            SyntaxKind.OPEN_BRACE@213..214 '{'
            SyntaxKind.WHITESPACE@214..223 '\n        '
            SyntaxKind.REQUIREMENTS_ITEM_NODE
              SyntaxKind.IDENT@223..232 'container'
              SyntaxKind.COLON@232..233 ':'
              SyntaxKind.WHITESPACE@233..234 ' '
              SyntaxKind.ABANDONED
                SyntaxKind.LITERAL_STRING_NODE
                  SyntaxKind.DOUBLE_QUOTE@234..235 '"'
                  SyntaxKind.LITERAL_STRING_TEXT@235..248 'ubuntu:latest'
                  SyntaxKind.DOUBLE_QUOTE@248..249 '"'
              SyntaxKind.WHITESPACE@249..254 '\n    '
              SyntaxKind.CLOSE_BRACE@254..255 '}'
            SyntaxKind.WHITESPACE@255..256 '\n'
            SyntaxKind.CLOSE_BRACE@256..257 '}'
          SyntaxKind.WHITESPACE@257..258 '\n'
Click to view example.wdl source
sprocket_bio/examples/example.wdl
version 1.3

task say_hello {
    input {
        String greeting
    }

    command <<<
        echo "~{greeting}, world!"
    >>>

    output {
        String out = read_string(stdout())
    }

    requirements {
        container: "ubuntu:latest"
    }
}