### Quick Start Example: Parsing Numbers and Expressions Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/README.md A simple example demonstrating how to define parsers for numbers and basic arithmetic expressions, then parse a string. ```scala import fastparse._ def number[$ : P]: P[Int] = P(CharsWhileIn("0-9").!.map(_.toInt)) def expr[$ : P]: P[Int] = P( number ~ ("+" ~ number).rep.map(_.sum) ) val result = parse("1 + 2 + 3", expr(_)) // Parsed.Success(6, 9) ``` -------------------------------- ### Start: Match Input Start Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/utility-parsers.md Succeeds only at the beginning of input (index 0) without consuming characters. Ensures parsing begins at the very start. ```scala def parseFromStart[$ : P] = P(Start ~ parser) // Ensures parsing begins at the very start ``` -------------------------------- ### Repeat Parser Examples Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/parser-operators.md Examples demonstrating the usage of the `rep` parser operator for lists, words, and CSV-like structures. ```scala def list[$ : P] = P("[" ~ items.rep(sep = ",") ~ "]") def words[$ : P] = P(word.rep(min = 1)) def csv[$ : P] = P(value.rep(sep = ",", min = 2, max = 10)) ``` -------------------------------- ### Example using isUpper Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/char-predicates.md Illustrates using isUpper with CharPred and CharsWhile to define a parser for keywords starting with an uppercase letter. ```Scala def keyword[$ : P] = P(CharPred(CharPredicates.isUpper) ~ CharsWhile(CharPredicates.isLower).?) // Matches identifiers starting with uppercase ``` -------------------------------- ### ASCII vs Unicode Predicate Examples Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/char-predicates.md Demonstrates the Unicode-aware nature of CharPredicates.isLetter and CharPredicates.isDigit with examples from different scripts. ```Scala CharPredicates.isLetter('a') // true (ASCII) CharPredicates.isLetter('α') // true (Greek) CharPredicates.isLetter('中') // true (Chinese) CharPredicates.isDigit('5') // true (ASCII) CharPredicates.isDigit('٥') // true (Arabic-Indic) ``` -------------------------------- ### Raw Repeat Parser Example Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/parser-operators.md Example of using `repX` to match exactly four hexadecimal digits without consuming intervening whitespace. ```scala def hexString[$ : P] = P(CharIn("0-9a-f").repX(exactly = 4)) ``` -------------------------------- ### Example using isMathSymbol Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/char-predicates.md Demonstrates how to use the isMathSymbol predicate with CharPred to define a parser for mathematical operators. ```Scala def mathOp[$ : P] = P(CharPred(CharPredicates.isMathSymbol)) ``` -------------------------------- ### Example using isPrintableChar Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/char-predicates.md Illustrates using isPrintableChar with CharsWhile to parse a sequence of printable characters. ```Scala def text[$ : P] = P(CharsWhile(CharPredicates.isPrintableChar).!) ``` -------------------------------- ### JSON Parser Example Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/getting-started.md A comprehensive example demonstrating how to parse JSON structures, including strings, numbers, booleans, null, arrays, and objects, with custom whitespace handling. ```scala implicit val ws = MultiLineWhitespace.whitespace def space[$: P] = P(CharsWhileIn(" \r\n", 0)) def string[$: P] = P(space ~ "\"" ~/ stringContents ~ "\"") def stringContents[$: P] = P((!"\"" ~ AnyChar).rep.!) def number[$: P] = P(space ~ CharsWhileIn("0-9") ~ ("-" ~ CharsWhileIn("0-9")).?).! def `null`[$: P] = P(space ~ "null") def bool[$: P] = P(space ~ ("true" | "false")) def value[$: P]: P[Any] = P( array(_) | obj(_) | string(_) | number(_) | bool(_) | `null`(_) ) def array[$: P] = P("[" ~/ value.rep(sep = ",") ~ "]") def pair[$: P] = P(string(_) ~ ":" ~/ value) def obj[$: P] = P("{" ~/ pair.rep(sep = ",") ~ "}") def json[$: P] = P(space ~ value ~ space ~ End) val result = parse("{\"name\": \"Alice\", \"age\": 30}", json(_)) ``` -------------------------------- ### Example using isLetter Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/char-predicates.md Shows how to use the isLetter predicate with CharPred and CharsWhile to define an identifier parser. ```Scala def identifier[$ : P] = P(CharPred(CharPredicates.isLetter) ~ CharsWhile(CharPredicates.isLetter).?) ``` -------------------------------- ### ParserInputSource Examples Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/parser-input.md Demonstrates using ParserInputSource with different input types: String, Iterator, and Reader. These examples show how fastparse can seamlessly handle various data sources. ```scala import fastparse._ // Works with String directly val result1 = parse("hello", parser(_)) // Works with Iterator (streaming) val chunks = Iterator("hel", "lo") val result2 = parse(chunks, parser(_)) // Works with Reader (e.g., from file) val reader = new java.io.FileReader("file.txt") val result3 = parse(reader, parser(_)) ``` -------------------------------- ### Opaque Parser Example Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/parser-operators.md Example of using `opaque` to wrap a repetition of whitespace characters, providing a generic 'whitespace' error message. ```scala def ws[$ : P] = P(" " | "\n" | "\t").rep.opaque("whitespace") ``` -------------------------------- ### Example using isDigit Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/char-predicates.md Demonstrates using isDigit with CharsWhile to parse a sequence of digits and map it to an integer. ```Scala def number[$ : P] = P(CharsWhile(CharPredicates.isDigit).!.map(_.toInt)) ``` -------------------------------- ### Positive Lookahead Example Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/parser-operators.md Example of using positive lookahead `&` to check for the presence of 'int' followed by whitespace before parsing 'int_variable'. ```scala def lookahead[$ : P] = P(&("int" ~ ws) ~ "int_variable") ``` -------------------------------- ### Example using isLower Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/char-predicates.md Shows how to use isLower with CharsWhile to parse a sequence of lowercase letters. ```Scala def lowercase[$ : P] = P(CharsWhile(CharPredicates.isLower).!) ``` -------------------------------- ### Streaming Parser Example with Iterator Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/parser-input.md An example of parsing streaming data from a file using IteratorParserInput. It also shows how to convert to IndexedParserInput for debugging or tracing. ```scala def streamingParser[$ : P] = P(line.rep) val lines = scala.io.Source.fromFile("huge.txt").getLines() val result = parse(lines, streamingParser(_)) // For debugging, convert to indexed first: val allLines = lines.toList val indexed = IndexedParserInput(allLines.mkString("\n")) val traced = parse(indexed, streamingParser(_)) ``` -------------------------------- ### Custom ParserInput Implementation Example Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/parser-input.md Example of implementing a custom ParserInput for specialized use cases. This involves defining how to access characters, check reachability, slice data, and manage buffer operations. ```scala case class CustomInput(data: MyDataStructure) extends ParserInput { def apply(index: Int): Char = data.charAtIndex(index) def isReachable(index: Int): Boolean = index < data.length def slice(from: Int, until: Int): String = data.substring(from, until) def length: Int = data.length def innerLength: Int = length def dropBuffer(index: Int): Unit = {} // No-op for indexed def checkTraceable(): Unit = {} // Traceable def prettyIndex(index: Int): String = s"${index+1}" } val result = parse(CustomInput(...), parser(_)) ``` -------------------------------- ### Detailed Profiler Implementation Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/advanced-concepts.md An example implementation of a `DetailedProfiler` class that extends `Instrument` to record and analyze parsing times for different rules. ```scala class DetailedProfiler extends Instrument { private val times = scala.collection.mutable.Map[String, Vector[Long]]() def beforeParse(rule: String, index: Int) = { times(rule) = times.getOrElse(rule, Vector()) :+ System.nanoTime() } def afterParse(rule: String, index: Int, length: Int, success: Boolean) = { val before = times(rule).last val elapsed = System.nanoTime() - before times(rule) = times(rule).dropRight(1) :+ elapsed } def stats(rule: String): (Long, Double) = { val times = this.times.getOrElse(rule, Vector()) val sum = times.sum val avg = if (times.nonEmpty) sum.toDouble / times.size else 0.0 (sum, avg) } } ``` -------------------------------- ### Nested P Macro Names Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/advanced-concepts.md Illustrates how nested P() calls within a parser definition also get named and appear in the trace stack. In this example, both 'expr' and the individual '+' parser are named, contributing to a detailed error trace. ```Scala def expr[$ : P] = P( term ~ (P("+") ~ term).rep ) // Stack shows: "expr / term" and individual "+" parser ``` -------------------------------- ### Negative Lookahead Example Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/parser-operators.md Example of using negative lookahead `!` to ensure that the parsed identifier is not a keyword like 'if' or 'while'. ```scala def notKeyword[$ : P] = P( !"if" ~ !"while" ~ identifier) ``` -------------------------------- ### StringIn Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/basic-parsers.md Parses input if it starts with any of the provided strings in order. It's a fundamental parser for matching literal string sequences. ```APIDOC ## StringIn ### Description Parses input if it starts with any of the provided strings in order. It's a fundamental parser for matching literal string sequences. ### Parameters #### Path Parameters - **s** (String*) - Required - Strings to match; tried in order - **ctx** (P[_]) - Implicit - Parsing context ### Return Type `P[Unit]` — succeeds if input starts with any string in the list ### Example ```scala def keyword[$ : P] = P(StringIn("if", "while", "for", "class")) def operator[$ : P] = P(StringIn("==", "!=", "<=", ">=", "+", "-")) ``` ``` -------------------------------- ### Java-like Parsers with Implicit Whitespace Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/advanced-concepts.md An example implementation of `ParserDef` for Java-like syntax, specifying its own implicit whitespace. ```scala object JavaLikeParsers extends ParserDef { implicit val ws = JavaWhitespace.whitespace def expr[$ : P] = P(term ~ ("+" ~ term).rep) // ... rest of parsers } ``` -------------------------------- ### Expression Parser using Common Parsers Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/advanced-concepts.md An example of building a simple expression parser (expr, term, factor) that reuses parsers from the CommonParsers library. ```scala object MyParser { import CommonParsers._ def expr[$ : P] = P(term ~ ("+" ~ term).rep) def term[$ : P] = P(factor ~ ("*" ~ factor).rep) def factor[$ : P] = P(number(_) | ident(_) | "(" ~/ expr ~ ")") } ``` -------------------------------- ### Scala-like Parsers with Implicit Whitespace Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/advanced-concepts.md An example implementation of `ParserDef` for Scala-like syntax, specifying its own implicit whitespace. ```scala object ScalaLikeParsers extends ParserDef { implicit val ws = ScalaWhitespace.whitespace def expr[$ : P] = P(term ~ ("+" ~ term).rep) // ... rest of parsers } ``` -------------------------------- ### Sequencer[T, V, R]: Tuple Sequencing Example Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/types.md Demonstrates how the Sequencer trait combines results of sequential parsers, handling tuple construction, unit elimination, and type-safe nesting. ```Scala def tuple3[$ : P] = P(a ~ b ~ c) // a: P[String], b: P[Int], c: P[Boolean] // Result: P[(String, Int, Boolean)] ``` ```Scala def withUnit[$ : P] = P(a ~ "," ~ b) // a: P[String], "," returns Unit, b: P[String] // Result: P[(String, String)] (comma discarded) ``` ```Scala def discardAll[$ : P] = P("a" ~ "b" ~ "c") // All three return Unit // Result: P[Unit] ``` -------------------------------- ### Parse a hexadecimal number without spaces Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/whitespace-strategies.md This example demonstrates using NoWhitespace to ensure that a hexadecimal number prefix ('0x') is immediately followed by hexadecimal digits, without any spaces. ```Scala implicit val ws = NoWhitespace.whitespace def hexNumber[$ : P] = P("0x" ~ CharsWhileIn("0-9a-f")) ``` -------------------------------- ### Custom Profiling Instrument Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/types.md Implements a `ProfilingInstrument` to track the execution time of parsers. It records the start time before a parser runs and calculates the elapsed time after it completes, printing statistics. ```Scala class ProfilingInstrument extends Instrument { private val times = scala.collection.mutable.Map[String, Long]() def beforeParse(rule: String, index: Int) = { times(rule) = System.nanoTime() } def afterParse(rule: String, index: Int, length: Int, success: Boolean) = { val elapsed = System.nanoTime() - times(rule) println(f"$rule% 20s: $elapsed%10d ns ($length chars, $success)") } } val profiler = new ProfilingInstrument() val result = parse(input, parser(_), instrument = profiler) ``` -------------------------------- ### parse Function Signature and Usage Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/parse-function.md The `parse` function is the main entry point for using fastparse. It takes an input source and a parser function, and returns a `Parsed[T]` result. This snippet illustrates its signature, parameters, and various usage examples including string parsing, verbose error reporting, custom whitespace, streaming input, and file input. ```APIDOC ## parse Function ### Description The primary entry point for parsing. Runs a parser against an input source and returns a `Parsed[T]` result containing either a success value with the final index, or a failure with debugging metadata. ### Signature ```scala def parse[T]( input: ParserInputSource, parser: P[_] => P[T], verboseFailures: Boolean = false, startIndex: Int = 0, instrument: Instrument = null ): Parsed[T] ``` ### Parameters | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | input | ParserInputSource | Yes | — | The input to parse. Accepts String, Iterator[String], or any type with a geny.Readable implicit conversion | | parser | P[_] => P[T] | Yes | — | A parser function that accepts a parsing context and returns a parser for type T | | verboseFailures | Boolean | No | false | When true, collects detailed error messages. Slows down parsing ~2x but provides better diagnostics without needing `.trace()` | | startIndex | Int | No | 0 | The character position in the input to begin parsing | | instrument | Instrument | No | null | Optional callbacks invoked before and after each named `P(...)` parser for profiling/tracing | ### Return Type `Parsed[T]` — A sealed type containing either: - `Parsed.Success[T]`: Contains the parsed value and final index position - `Parsed.Failure`: Contains error message, failure index, and extra metadata for tracing ### Usage Examples #### Basic string parsing ```scala import fastparse._ def number[$ : P] = P(CharsWhileIn("0-9").!) val result = parse("42", number(_)) // result: Parsed.Success("42", 2) or Parsed.Failure ``` #### Parsing with verboseFailures for better errors ```scala def expr[$ : P] = P("x" | "y" | "z") val result = parse("a", expr(_), verboseFailures = true) // If it fails, you get detailed information about what was expected ``` #### Parsing with custom whitespace ```scala implicit val ws = SingleLineWhitespace.whitespace def statement[$ : P] = P("if" ~ "(" ~ expr ~ ")") val result = parse("if (expr)", statement(_)) ``` #### Parsing an iterator of strings (streaming) ```scala def word[$ : P] = P(CharsWhileIn("a-z").!) val chunks = Iterator("hel", "lo") val result = parse(chunks, word(_)) ``` #### Parsing from a file-like source ```scala import java.io.FileReader val reader = new FileReader("file.txt") val result = parse(reader, parser(_)) ``` ### Error Handling Check the `Parsed.Failure` case for detailed error information: ```scala parse("input", parser(_)) match { case success: Parsed.Success[T] => println(s"Parsed: ${success.value} at index ${success.index}") case failure: Parsed.Failure => println(failure.msg) val traced = failure.trace() println(traced.aggregateMsg) } ``` ``` -------------------------------- ### Literal String Parser Example Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/basic-parsers.md Parses an exact string value. Applied implicitly when a string literal appears in parser context. ```scala import fastparse._ def json[$ : P] = P("{" ~ pairs ~ "}") // "{" is implicitly a LiteralStr parser ``` -------------------------------- ### Custom ASCII-only predicates Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/char-predicates.md Provides examples of defining custom inline functions for ASCII-specific letter and digit checks. ```Scala def asciiLetter(c: Char) = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') def asciiDigit(c: Char) = c >= '0' && c <= '9' ``` -------------------------------- ### Parsing Scala CLI Arguments Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/getting-started.md Parses command-line arguments provided as a single string, typically by joining `args` array. This example defines a parser for flag-style arguments like `--name=value`. ```scala // Parse CLI arguments def flagParser[$ : P] = P( ("--" ~ CharsWhile(_.isLetter).! ~ "=" ~ CharsWhile(c => c != ' ').!).rep ) parse(args.mkString(" "), flagParser(_)) ``` -------------------------------- ### Detailed Failure Analysis with Trace Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/logging-debugging.md When a parse fails, you can use `.trace()` on the `Parsed.Failure` object to get rich error information, including aggregate and terminal messages. This is useful for understanding why a parse failed. ```scala val result = parse("{broken", jsonParser(_)) result match { case f: Parsed.Failure => println("Quick error: " + f.msg) val traced = f.trace() println("Aggregate: " + traced.aggregateMsg) println("Terminals: " + traced.terminalsMsg) // With full context: println("Long aggregate: " + traced.longAggregateMsg) case _ => () } ``` -------------------------------- ### Streaming Parse with Iterator Input Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/parse-function.md Parses input provided as an `Iterator[String]`, enabling streaming of data for large inputs. This example defines a simple word parser. ```scala def word[$ : P] = P(CharsWhileIn("a-z").!) val chunks = Iterator("hel", "lo") val result = parse(chunks, word(_)) ``` -------------------------------- ### Enable Runtime Logging with log Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/logging-debugging.md Wrap a parser with `.log` to print its execution details, including start/end times, input index, and success/failure status. Useful for interactive debugging. ```scala def expr[$ : P]: P[Expr] = P( number.log ~ ("+" ~/ number.log).rep ) // Output for input "1 + 2": // +number:0:0 // -number:0:0:Success(1:0, cut) // +(3) "+" call at position 3 // ... ``` -------------------------------- ### Parsing from File-like Source Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/parse-function.md Demonstrates parsing input directly from a file-like source, such as a `java.io.FileReader`, without needing to load the entire file into memory. ```scala import java.io.FileReader val reader = new FileReader("file.txt") val result = parse(reader, parser(_)) ``` -------------------------------- ### Correct Parser Naming with P() Macro Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/getting-started.md Illustrates the correct way to name parsers using the `P()` macro, which automatically captures the method name. Avoids issues where parser names are unknown. ```scala // Good: P() macro captures method name def expr[$ : P] = P("a" | "b" | "c") ``` -------------------------------- ### Add Error Context with Index Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/README.md Parses a value and captures its start and end indices for error reporting. ```scala def positioned[$ : P] = P(Index ~ parser ~ Index).map { case (start, value, end) => Located(value, start, end) } ``` -------------------------------- ### Basic String Parsing with fastparse Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/parse-function.md Demonstrates parsing a simple string input using a defined number parser. The result is either a success with the parsed value and index, or a failure. ```scala import fastparse._ def number[$ : P] = P(CharsWhileIn("0-9").!) val result = parse("42", number(_)) // result: Parsed.Success("42", 2) or Parsed.Failure ``` -------------------------------- ### Parse configuration with script-style whitespace and comments Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/whitespace-strategies.md The ScriptWhitespace strategy handles standard whitespace plus '#' line comments. It's designed for syntaxes like Bash or Python. ```Scala implicit val ws = ScriptWhitespace.whitespace def config[$ : P] = P( setting.rep ~ End ) ``` -------------------------------- ### Whitespace Handling Strategies Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/getting-started.md Demonstrates different strategies for handling whitespace and comments within parsers, including no whitespace, single-line, multi-line, script-style, Java-style, and Scala-style comments. ```scala // No whitespace implicit val ws = NoWhitespace.whitespace // Only spaces and tabs (for line-sensitive grammars) implicit val ws = SingleLineWhitespace.whitespace // All whitespace (default for most languages) implicit val ws = MultiLineWhitespace.whitespace // Script-style (# comments) implicit val ws = ScriptWhitespace.whitespace // Java-style (// and /* */ comments) implicit val ws = JavaWhitespace.whitespace // Scala-style (nested /* */ comments) implicit val ws = ScalaWhitespace.whitespace ``` -------------------------------- ### Character Sequence Parsers Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/basic-parsers.md Parses one or more consecutive characters satisfying a predicate. Can be captured with '!' to get the string. ```scala def identifier[$ : P] = P(CharsWhile(_.isLetter).!) def whitespace[$ : P] = P(CharsWhile(_.isWhitespace)) def number[$ : P] = P(CharsWhile(_.isDigit, min = 1).!) ``` -------------------------------- ### Handle Parsing Success and Failure Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/README.md Demonstrates how to match on the result of a parse operation, handling both successful parses and failures with detailed error tracing. ```scala parse(input, parser(_)) match { case Parsed.Success(value, index) => // Successfully parsed value println(s"Got: $value") case f: Parsed.Failure => // Quick diagnosis println(f"Error: ${f.msg}") // For development, get detailed diagnostics val traced = f.trace() println(f"Expected: ${traced.aggregateMsg}") println(f"Options: ${traced.terminalsMsg}") } ``` -------------------------------- ### Implement Custom Logger Interface Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/logging-debugging.md Implement the `Logger` trait to customize where log output is sent. Examples include logging to a StringBuilder or a file. ```scala class StringBuilderLogger(sb: StringBuilder) extends Logger { def f(s: String) = { sb.append(s) sb.append("\n") } } class FileLogger(path: String) extends Logger { private val writer = new java.io.FileWriter(path) def f(s: String) = { writer.write(s) writer.write("\n") writer.flush() } } // Use with logging: val logs = StringBuilder() implicit val logger: Logger = new StringBuilderLogger(logs) val result = parse(input, parser(_)) println(logs.toString()) ``` -------------------------------- ### Configure Whitespace and Comments Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/README.md Sets up implicit whitespace handling that also skips comments. ```scala implicit val ws = JavaWhitespace.whitespace // Automatically skips // and /* */ comments ``` -------------------------------- ### Benchmark Comparison: slow, fast, medium Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/char-predicates.md Compares the performance of different approaches for parsing digits using CharsWhile with a lambda, CharsWhileIn, and CharsWhile with a pre-computed predicate. ```Scala // Slower: function call per character def slow[$ : P] = P(CharsWhile(_.isDigit)) // Faster: lookup table def fast[$ : P] = P(CharsWhileIn("0-9")) // Medium: pre-computed predicate def medium[$ : P] = P(CharsWhile(CharPredicates.isDigit)) ``` -------------------------------- ### IndexedParserInput Creation and Usage Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/parser-input.md Shows how to create and use IndexedParserInput for String inputs, which is efficient for in-memory data and supports full tracing. ```scala val input = IndexedParserInput("hello world") val result = parse(input, parser(_)) // Or implicitly: val result = parse("hello world", parser(_)) ``` -------------------------------- ### Index: Get Current Position Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/utility-parsers.md Always succeeds with the current index in the input, consuming no characters. Useful for tracking source locations for error reporting. ```scala def positioned[$ : P] = P(Index ~ parser ~ Index).map { case (start, value, end) => AstNode(value, start, end) } ``` -------------------------------- ### Visual Tracing with Logging Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/advanced-concepts.md Enables visual tracing of parser execution by logging each step. Use this for debugging complex parsing logic by observing the indented execution tree. ```Scala implicit val logger = Logger.stdout def expr[$ : P]: P[Expr] = P( term.log ~ ("+" ~ term.log).rep.log ) parse("1 + 2 + 3", expr(_)) // Shows indented execution tree ``` -------------------------------- ### Basic FastParse Parser Structure Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/getting-started.md Illustrates the fundamental structure of a fastparse parser, including imports, parser definition, input, and result handling. This pattern is applicable to most parsing tasks. ```scala import fastparse._ def myParser[$ : P]: P[ResultType] = P( // ... parser combinators ... ) val input = "text to parse" val result = parse(input, myParser(_)) result match { case Parsed.Success(value, index) => println(s"Parsed: $value") case f: Parsed.Failure => println(s"Failed: ${f.msg}") } ``` -------------------------------- ### Parsing with Custom Whitespace Handling Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/parse-function.md Shows how to define and use custom whitespace handling, such as `SingleLineWhitespace.whitespace`, within the parsing process. ```scala implicit val ws = SingleLineWhitespace.whitespace def statement[$ : P] = P("if" ~ "(" ~ expr ~ ")") val result = parse("if (expr)", statement(_)) ``` -------------------------------- ### Mutual Recursion for Expression Parsing Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/getting-started.md Define mutually recursive parsers for arithmetic expressions. This example shows a slightly different syntax for mutual recursion compared to direct recursion, but achieves the same goal. ```scala def expr[$ : P]: P[Expr] = P(term ~ ("+" ~ term).rep) def term[$ : P]: P[Expr] = P(factor ~ ("*" ~ factor).rep) def factor[$ : P]: P[Expr] = P("(" ~/ expr ~ ")" | number(_)) ``` -------------------------------- ### Detailed Failure Analysis (Debugging Workflow) Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/logging-debugging.md This snippet demonstrates how to obtain and print detailed failure messages using `f.trace().aggregateMsg` and `f.trace().terminalsMsg` for in-depth debugging. ```scala parse(input, parser(_)) match { case f: Parsed.Failure => val traced = f.trace() println(traced.aggregateMsg) println(traced.terminalsMsg) } ``` -------------------------------- ### Optioner for Optional String Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/types.md Demonstrates the `Optioner` behavior for `String` types, where the parsed element is wrapped in `Some` if present and `None` if absent. This is useful for parsing optional string components. ```Scala def opt2[$ : P] = P(CharsWhileIn("0-9").!.?) // Returns P[Option[String]] ``` -------------------------------- ### Index Tracking for Position Information Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/advanced-concepts.md Captures the start and end indices of parsed elements. Use the `located` combinator to retrieve positional information alongside parsed values, useful for error reporting or AST generation. ```Scala def located[T](p: P[T]): P[(T, Int, Int)] = P( Index ~ p ~ Index ).map { case (start, v, end) => (v, start, end) } def expr[$ : P] = P(located(term) ~ located("+" ~/ term).rep) ``` -------------------------------- ### flatMap for Sequential Dependency Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/advanced-concepts.md Demonstrates using flatMap to create a sequential dependency between parsers. After parsing a 'typeChar', the flatMap's lambda is executed, which then chooses and parses a specific value parser ('intValue', 'strValue', or 'boolValue') based on the 'typeChar'. ```Scala def typedValue[$ : P]: P[Value] = P( typeChar.flatMap { case 'i' => P("int:") ~/ intValue(_) case 's' => P("str:") ~/ strValue(_) case 'b' => P("bool:") ~/ boolValue(_) } ) // Input: "i:42" // - Parse typeChar: 'i' // - flatMap decides to parse intValue // - Result: IntValue(42) ``` -------------------------------- ### Whitespace in String Literals Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/advanced-concepts.md Illustrates how string literals in FastParse implicitly consume trailing whitespace according to the active whitespace rule. In this example, using 'SingleLineWhitespace.whitespace', both "if" and "(" will consume any following single-line whitespace. ```Scala implicit val ws = SingleLineWhitespace.whitespace def stmt[$ : P] = P("if" ~ "(" ~ condition ~ ")") // "if" consumes trailing space // "(" consumes trailing space // etc. ``` -------------------------------- ### Optioner for Unit Handling Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/types.md Demonstrates the `Optioner` behavior for `Unit` types, where the presence or absence of the parsed element does not affect the result, which remains `()`. This is useful when you only care if a pattern *can* appear, but not its value. ```Scala def opt1[$ : P] = P(("a" | "b").?) // Returns P[Unit] (presence/absence doesn't matter) ``` -------------------------------- ### Custom Logger Implementation Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/types.md Shows how to implement a custom `Logger` by extending the `Logger` trait and appending output to a `StringBuilder`. This allows for capturing and inspecting log output programmatically. ```Scala case class MyLogger(output: StringBuilder) extends Logger { def f(s: String) = output.append(s).append("\n") } val logs = StringBuilder() implicit val logger: Logger = MyLogger(logs) val result = parse("input", parser(_)) println(logs.toString()) ``` -------------------------------- ### Multiple String Alternatives Parser Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/basic-parsers.md Efficiently parses any one of the provided strings. More efficient than chaining alternatives with '|'. ```scala def StringIn(s: String*)(implicit ctx: P[_]): P[Unit] ``` -------------------------------- ### Detailed Failure Trace Extraction Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/getting-started.md Demonstrates how to obtain a detailed trace of a parsing failure, including the index, expected tokens, and the input slice at the failure point. ```scala parse(input, parser(_)) match { case Parsed.Success(v, _) => Right(v) case f: Parsed.Failure => val traced = f.trace() Left(ParseError( index = traced.index, expected = traced.aggregateMsg, found = traced.input.slice(traced.index, traced.index + 20) )) } ``` -------------------------------- ### Performance Profiling with SimpleProfiler Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/logging-debugging.md A simplified `Instrument` implementation that logs slow parsers (over 1ms) by measuring the time taken between `beforeParse` and `afterParse` calls. ```scala class SimpleProfiler extends Instrument { private val times = scala.collection.mutable.Map[String, Long]() def beforeParse(rule: String, index: Int) = { times(rule) = System.nanoTime() } def afterParse(rule: String, index: Int, length: Int, success: Boolean) = { val elapsed = System.nanoTime() - times(rule) if (elapsed > 1_000_000) { // Only slow parsers println(f"Slow: $rule%20s $elapsed%10d ns") } } } parse(input, parser(_), instrument = new SimpleProfiler()) ``` -------------------------------- ### Parse configuration with Jsonnet-style whitespace and comments Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/whitespace-strategies.md The JsonnetWhitespace strategy combines script-style '#' line comments and Java-style '/* */' block comments (non-nested) with standard whitespace. It's tailored for Jsonnet syntax. ```Scala implicit val ws = JsonnetWhitespace.whitespace def config[$ : P] = P(field.rep) ``` -------------------------------- ### Left Recursion Avoidance using .rep Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/getting-started.md Demonstrates the correct way to handle left recursion in fastparse by using the `.rep` combinator instead of direct left-recursive definitions, which are not supported. ```scala // DO: def expr[$ : P] = P(term ~ ("+" ~ term).rep) ``` -------------------------------- ### Handling Parse Results (Success and Failure) Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/parse-function.md Illustrates how to pattern match on the `Parsed` result to differentiate between successful parses and failures, accessing details like the parsed value, index, and error messages. ```scala parse("input", parser(_)) match { case success: Parsed.Success[T] => println(s"Parsed: ${success.value} at index ${success.index}") case failure: Parsed.Failure => println(failure.msg) val traced = failure.trace() println(traced.aggregateMsg) } ``` -------------------------------- ### Quick Parse Test Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/logging-debugging.md A basic test to quickly check if a parse succeeds or fails, printing the success value or the failure message. ```scala parse(input, parser(_)) match { case s: Parsed.Success[T] => println(s"Success: ${s.value}") case f: Parsed.Failure => println(s"Failed: ${f.msg}") } ``` -------------------------------- ### StringIn Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/basic-parsers.md Efficiently parses any one of the provided strings. This is more performant than chaining multiple alternative parsers using the `|` operator. ```APIDOC ## StringIn: Multiple String Alternatives ### Description Efficiently parses any one of the provided strings. More efficient than chaining alternatives with `|`. ### Signature ```scala def StringIn(s: String*)(implicit ctx: P[_]): P[Unit] ``` ### Parameters - **s** (String*) - Required - Strings to choose from for parsing. - **ctx** (P[_]) - Implicit - Parsing context ### Return Type `P[Unit]` — succeeds if any of the provided strings match at the current position. ``` -------------------------------- ### ReaderParserInput Creation and Usage Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/parser-input.md Illustrates how to use ReaderParserInput with a java.io.Reader, which is automatically handled by fastparse for file I/O and other reader sources. ```scala // Automatically used by parse(): import java.io.FileReader val reader = new FileReader("file.txt") val result = parse(reader, parser(_)) // Or explicitly: val input = ReaderParserInput(reader, bufferSize = 4096) ``` -------------------------------- ### Sequencer for Tuple Combination Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/advanced-concepts.md Demonstrates how Sequencer combines results from sequential parsers into tuples. It shows how intermediate Unit results are eliminated. ```scala def triple[$ : P] = P(a ~ b ~ c) // Sequencer[String, Int, (String, Int)] for a ~ b // Then Sequencer[(String, Int), Boolean, (String, Boolean)] for ~ c def optionalMid[$ : P] = P(a ~ "," ~ c) // a returns String, "," returns Unit, c returns Boolean // Result: Sequencer[String, (Unit, Boolean), (String, Boolean)] // Unit is eliminated, giving (String, Boolean) ``` -------------------------------- ### StringInIgnoreCase Parser for Keywords Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/basic-parsers.md Defines parsers for SQL keywords using StringInIgnoreCase for case-insensitive matching. ```Scala def keyword[$ : P] = P(StringInIgnoreCase("SELECT", "FROM", "WHERE")) def bool[$ : P] = P(StringInIgnoreCase("true", "false").!.map(_.toLowerCase.toBoolean)) ``` -------------------------------- ### StringIn Parser for Keywords Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/basic-parsers.md Defines parsers for common keywords using StringIn for exact string matching. ```Scala def keyword[$ : P] = P(StringIn("if", "while", "for", "class")) def operator[$ : P] = P(StringIn("==", "!=", "<=", ">=", "+", "-")) ``` -------------------------------- ### IteratorParserInput Creation and Usage Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/parser-input.md Demonstrates creating and using IteratorParserInput for streaming input from an Iterator. This is suitable for large inputs but does not support tracing. ```scala implicit def FromIterator(s: Iterator[String]): IteratorParserInput = IteratorParserInput(s) val result = parse(Iterator("chunk1", "chunk2"), parser(_)) ``` -------------------------------- ### Optional Parsers Returning Option vs. Unit Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/getting-started.md Distinguishes between optional parsers that return `Option[T]` (e.g., `word.?`) and those that return `Unit` (e.g., `("a" | "b").?`). Use the appropriate type based on whether you need to capture the parsed value. ```scala // Returns P[Unit] - optional but value is always () def opt1[$ : P] = P(("a" | "b").?) // Returns P[Option[String]] - optional with Some/None def opt2[$ : P] = P(word.?) ``` -------------------------------- ### Usage in CharsWhile Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/char-predicates.md Demonstrates common patterns for using CharsWhile with isLetter and isDigit predicates. ```Scala def word[$ : P] = P(CharsWhile(CharPredicates.isLetter).!) def number[$ : P] = P(CharsWhile(CharPredicates.isDigit).!) ``` -------------------------------- ### Repeater for Unit Accumulation Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/types.md Demonstrates the default `Repeater` behavior for accumulating `Unit` values, where repeats produce no values and return `()`. This is useful when only the repetition count matters, not the values themselves. ```Scala def units[$ : P] = P(("a" | "b").rep) // Returns P[Unit] (values are discarded) ``` -------------------------------- ### Profiling Parser Performance with Instrument Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/logging-debugging.md Implement the `Instrument` trait to profile parser performance. The `beforeParse` and `afterParse` methods are called before and after each named parser, allowing you to measure execution times and track coverage. ```scala class ProfilingInstrument extends Instrument { private val times = scala.collection.mutable.Map[String, Long]() private val counts = scala.collection.mutable.Map[String, Int]() def beforeParse(rule: String, index: Int) = { counts(rule) = counts.getOrElse(rule, 0) + 1 times(rule) = System.nanoTime() } def afterParse(rule: String, index: Int, length: Int, success: Boolean) = { val elapsed = System.nanoTime() - times(rule) // Accumulate statistics } def report(): Unit = { counts.foreach { case (rule, count) => println(f"$rule%20s: $count%5d calls") } } } val profiler = new ProfilingInstrument() parse(input, parser(_), instrument = profiler) profiler.report() ``` -------------------------------- ### Profiling Parser Performance Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/getting-started.md Implements a custom `Instrument` to measure and report the execution time of parser rules, helping to identify performance bottlenecks. ```scala class TimingInstrument extends Instrument { private val times = scala.collection.mutable.Map[String, Long]() def beforeParse(rule: String, index: Int) = { times(rule) = System.nanoTime() } def afterParse(rule: String, index: Int, length: Int, success: Boolean) = { val elapsed = System.nanoTime() - times(rule) if (elapsed > 100_000) println(f"$rule%20s: ${elapsed/1000}%6.0f µs") } } parse(input, parser(_), instrument = new TimingInstrument()) ``` -------------------------------- ### Optioner with Sign and Number Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/types.md Illustrates `Optioner` usage where a signed number is parsed. Since `sign` returns `Unit`, its optionality results in `P[Unit]`, leading to a final parser type of `P[(Unit, Int)]`. ```Scala def opt3[$ : P] = P(sign.? ~ number) // sign returns Unit, so option is P[Unit] // Result: P[(Unit, Int)] ``` -------------------------------- ### Custom Whitespace Implementation Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/whitespace-strategies.md Defines custom whitespace rules, including skipping spaces, tabs, and '--' line comments. This allows for tailored parsing behavior. ```Scala object CustomWhitespace { implicit object whitespace extends Whitespace { def apply(ctx: ParsingRun[_]): ParsingRun[Unit] = { val input = ctx.input var index = ctx.index while (input.isReachable(index)) { val ch = input(index) if (ch == ' ' || ch == '\t') { index += 1 } else if (index + 1 < input.length && input(index) == '-' && input(index + 1) == '-') { // Skip -- line comments while (input.isReachable(index) && input(index) != '\n') { index += 1 } } else { // Found non-whitespace ctx.freshSuccessUnit(index) return ctx } } ctx.freshSuccessUnit(index) } } } implicit val ws = CustomWhitespace.whitespace def expr[$ : P] = P(term ~ ("+" ~ term).rep) ``` -------------------------------- ### Raw Sequence Parser with Cut: ~~/ Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/parser-operators.md Combines raw sequence parsing with a cut, preventing backtracking past the cut point if the first parser succeeds. ```Scala def ~~/[V, R](other: P[V]) (implicit s: Implicits.Sequencer[T, V, R], ctx: P[_]): P[R] ``` -------------------------------- ### Usage in CharsWhileIn Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/char-predicates.md Illustrates using CharsWhileIn for character class matching, noting its efficiency over CharPred for fixed sets. ```Scala def digit[$ : P] = P(CharsWhileIn("0-9")) // More efficient than CharPred def letter[$ : P] = P(CharsWhileIn("a-zA-Z")) // More efficient than CharPred ``` -------------------------------- ### ParsingRun[T]: Parser Context Usage Pattern Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/types.md Parsers receive a ParsingRun[_] context and return a P[T]. The context object holds both immutable configuration and mutable runtime state for an in-progress parse. ```Scala def expr[$ : P]: P[Int] = { val ctx = summon[P[_]] // Get implicit ParsingRun context // ... parser implementation modifies ctx fields ... ctx.asInstanceOf[P[Int]] } ``` -------------------------------- ### Capture a Word Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/README.md Defines a parser that captures a sequence of letters as a word. ```scala def word[$ : P] = P(CharsWhile(_.isLetter).!) ``` -------------------------------- ### Enabling Parser Logging Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/getting-started.md Configures a logger to output a detailed, indented trace of the parsing process, aiding in debugging parser logic. ```scala implicit val logger = Logger.stdout def expr[$ : P]: P[Expr] = P( term.log ~ ("+" ~ term.log).rep ) parse(input, expr(_)) // Prints indented parse trace ``` -------------------------------- ### Sequence Parser with Whitespace: ~ Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/parser-operators.md Runs two parsers in sequence, consuming optional whitespace between them. Combines results into a tuple if both succeed. ```Scala def ~/[V, R](other: P[V]) (implicit s: Implicits.Sequencer[T, V, R], whitespace: Whitespace, ctx: P[_]): P[R] ``` ```Scala def pair[$ : P] = P(word ~ "=" ~ word) // word ~ "=" ~ word produces (wordValue, unitValue, wordValue) tuple ``` -------------------------------- ### Pattern Matching on Parsed Result Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/parsed-results.md Demonstrates how to pattern match on the result of a parse operation to handle both successful and failed outcomes. Alternatively, the `fold` method can be used for a functional approach. ```scala val result = parse("42", number(_)) result match { case s: Parsed.Success[Int] => println(s"Parsed: ${s.value}") case f: Parsed.Failure => println(f"Failed: ${f.msg}") } // Or use fold for functional style: val outcome = result.fold( (msg, idx, extra) => s"Error at $idx: $msg", (value, idx) => s"Success: $value at $idx" ) ``` -------------------------------- ### Custom Sequencing with Map Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/types.md Use `map` for non-tuple results in custom sequencing. ```Scala def triple[$ : P] = P((a ~ b ~ c).map { case (x, y, z) => MyTriple(x, y, z) }) ``` -------------------------------- ### flatMapX for Whitespace-Agnostic Lookahead Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/advanced-concepts.md Explains flatMapX as an alternative to flatMap that does not consume whitespace after the initial parser. This is useful for lookahead scenarios where the decision logic depends on the next character but should not consume it or any following whitespace. ```Scala def jsonValue[$ : P]: P[JsonValue] = P( SingleChar.flatMapX { case '{' => jsonObj(_) case '[' => jsonArray(_) case '"' => jsonString(_) } ) // Like flatMap but no whitespace after SingleChar ``` -------------------------------- ### Quick Failure Message Extraction Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/getting-started.md Shows how to extract a concise failure message from a parsing result. This is useful for simple error reporting. ```scala parse(input, parser(_)) match { case Parsed.Success(value, _) => Right(value) case f: Parsed.Failure => Left(f.msg) } ``` -------------------------------- ### Handling Ambiguous Operator Precedence Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/getting-started.md Demonstrates how to resolve ambiguous operator precedence in parsers by using explicit grouping with parentheses. This ensures the parser interprets the alternatives correctly. ```scala // Use explicit grouping if unclear: def alt[$ : P] = P((a ~ b) | (c ~ d)) ``` -------------------------------- ### Cut Operator in Alternation Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/advanced-concepts.md Demonstrates the use of the cut operator '/' in an alternation to commit to a specific branch (e.g., 'ifStatement') once its initial part succeeds. This prevents backtracking to other alternatives like 'whileStatement' or 'assignment' if subsequent parsing fails, improving performance and error reporting. ```Scala def statement[$ : P] = P( ifStatement(_) | whileStatement(_) | assignment(_) ) def ifStatement[$ : P] = P( "if" / "(" ~ condition ~ ")" ~ body ) // The / after "if" commits to ifStatement branch // If subsequent parsing fails, won't backtrack to try while/assignment ``` -------------------------------- ### Parse a function with Java/C-style whitespace and comments Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/whitespace-strategies.md The JavaWhitespace strategy consumes standard whitespace, '//' line comments, and '/* */' block comments (non-nested). It's suitable for Java, C, and similar languages. ```Scala implicit val ws = JavaWhitespace.whitespace def function[$ : P] = P( type ~ name ~ "(" ~ params ~ ")" ~ body ) ``` -------------------------------- ### Character Sequence Parsers Source: https://github.com/com-lihaoyi/fastparse/blob/master/_autodocs/getting-started.md Parsers for matching sequences of characters based on character sets or predicates, capturing the matched sequence as a string. ```scala def number[$ : P] = P(CharsWhileIn("0-9").!) def word[$ : P] = P(CharsWhile(_.isLetter).!) ```