### Using .node() to Create a Parse Node Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/tutorial.md Demonstrates how to use the built-in `.node()` method on a parser to wrap its result in a `ParseNode` object, including start and end location information (index, line, column) and a custom name. ```ts const number = bnb .match(/[0-9]+/) .map(Number) .node("Number"); number.tryParse("8675309"); // => { // type: "ParseNode", // name: "Number", // value: 8675309, // start: { index: 0, line: 1, column: 1 }, // end: { index: 7, line: 1, column: 8 } // } ``` -------------------------------- ### Parsing Static Strings with bnb.text and .and (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/tutorial.md Demonstrates how to create parsers for exact string literals using `bnb.text` and combine them sequentially using the `.and` method. The `.and` method returns the results of both parsers as an array. The example uses `.tryParse` to execute the parser and immediately get the result or throw an error on failure. ```ts const apple = bnb.text("apple"); const banana = bnb.text("banana"); const applebanana = apple.and(banana); ab.tryParse("applebanana"); // => ["apple", "banana"] ``` -------------------------------- ### Creating a Custom Node Function with bnb.location Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/tutorial.md Shows how to replicate the functionality of `.node()` by creating a custom function that uses `bnb.location` before and after a parser to capture start and end locations, then maps the result into a custom object structure. ```ts function node(type: string) { return function (parser: bnb.Parser) { return bnb .all(bnb.location, parser, bnb.location) .map(([start, value, end]) => { // You could also use classes instead of plain objects return { type, value, start, end }; }); }; } const number = bnb .match(/[0-9]+/) .map(Number) .thru(node("Number")); number.tryParse("8675309"); // => { // type: "Number", // value: 8675309, // start: { index: 0, line: 1, column: 1 }, // end: { index: 7, line: 1, column: 8 } // } ``` -------------------------------- ### Sequentially Combining Parsers with bnb.all (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md Parses all provided parsers in order, returning their results in an array. The parsers do not need to return the same type. This function is related to `parser.and`. The example demonstrates combining three text parsers and mapping the result into an object. ```typescript const abc = bnb .all(bnb.text("a"), bnb.text("b"), bnb.text("c")) .map(([first, second, third]) => { return { first, second, third }; }); abc.tryParse("abc"); // => { // first: "a", // second: "b", // third: "c", // } ``` -------------------------------- ### Choosing Among Parsers with bnb.choice (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md Attempts to parse using the provided parsers and returns the result of the first one that succeeds. Caution is advised with overlapping parsers; longer potential matches should be listed first. Related to `parser.or`. The examples illustrate basic usage and the issue with overlapping parsers. ```typescript const parser1 = bnb.choice(bnb.text("a"), bnb.text("b"), bnb.text("c")); parser1.tryParse("a"); // => "a" parser1.tryParse("b"); // => "b" parser1.tryParse("c"); // => "c" const parser2 = bnb.choice(bnb.text("abc"), bnb.text("abc-123")); parser2.tryParse("abc-123"); // => Error // // This fails because the first parser `abc` succeeds, but then there is still // the additional text `-123` afterward that is left unparsed. It is an error to // leave unparsed text after calling `.parse` or `.tryParse`. const parser3 = bnb.choice(bnb.text("abc-123"), bnb.text("abc")); parser3.tryParse("abc-123"); // => "abc-123" // // Since both parsers start with `abc`, we have to put the longer one first. ``` -------------------------------- ### Matching Exact Text with bnb.text (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md Returns a parser that matches the exact string supplied. This is typically used for parsing keywords or static characters. The examples show matching a single keyword and combining two text parsers. ```typescript const keywordWhile = bnb.text("while"); const paren = bnb.text("(").and(bnb.text(")")); keywordWhile.tryParse("while"); // => "while" paren.tryParse("()"); // => ["(", ")"] ``` -------------------------------- ### Matching Regular Expressions with bnb.match (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md Returns a parser that matches the entire regular expression at the current parser position. Supports 'i', 's', 'm', and 'u' flags. Note that the '^' anchor should not be used, and capture groups are not significant to the returned value. Examples show matching identifiers and numbers. ```typescript const identifier = bnb.match(/[a-z_]+/i); identifier.tryParse("internal_toString"); // => "internal_toString" const number = bnb.match(/[0-9]+/); number.tryParse("404"); // => 404 ``` -------------------------------- ### Attempting Parse and Getting Value or Throwing with parser.tryParse (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md The `parser.tryParse(input)` method is a convenience function that attempts to parse the input. If successful, it returns the parsed value directly. If the parse fails, it throws an error with a message detailing the location and expected values, suitable for cases where explicit failure handling is not needed. ```TypeScript const a = bnb.text("a"); a.tryParse("a"); // => "a" ``` -------------------------------- ### Handling Recursive Grammars with bnb.lazy (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md Takes a callback that returns a parser, delaying its evaluation until the parse action occurs. This is necessary for defining recursive grammars where parsers reference each other before they are fully defined. It's recommended to manually supply the type parameter when using `lazy` for better TypeScript inference. The example shows how to define a parser for nested lists. ```typescript type XExpr = XItem | XList; type XItem = string; type XList = XExpr[]; const expr: bnb.Parser = bnb.lazy(() => { return list.or(item); }); const item: bnb.Parser = bnb.match(/[a-z]+/i); const list: bnb.Parser = expr .sepBy(bnb.text(",")) .wrap(bnb.text("["), bnb.text("]")); expr.tryParse("[a,b,[c,d,[]],[[e]]]"); // => ["a", "b", ["c", "d", []], [["e"]]] ``` -------------------------------- ### Using bnb.choice for Multiple Options (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/tutorial.md Illustrates the use of `bnb.choice` as a concise way to combine multiple parsers, similar to chaining `.or`. It takes a list of parsers and returns the result of the first one that succeeds, also utilizing backtracking. ```TypeScript const a = bnb.text("a"); const b = bnb.text("b"); const c = bnb.text("c"); const abc = bnb.choice(a, b, c); abc.tryParse("a"); // => "a" abc.tryParse("b"); // => "b" abc.tryParse("c"); // => "c" ``` -------------------------------- ### Using bnb.all for Sequential Parsing (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/tutorial.md Shows `bnb.all` as a convenient alternative to nested `.chain` calls for parsing a fixed sequence of items. It takes multiple parsers as arguments and returns a new parser that yields an array containing the results of each parser in the order they were provided. ```TypeScript const oneChar = bnb.match(/./ms); const threeChars = bnb.all(oneChar, oneChar, oneChar); threeChars.tryParse("abc"); // => ["a", "b", "c"] ``` -------------------------------- ### Combining Parsers with .or (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/tutorial.md Shows how to use the `.or` method to create a parser that attempts multiple sub-parsers sequentially, returning the result of the first one that successfully parses the input. This method uses backtracking to reset the source location if a parser fails. ```TypeScript const a = bnb.text("a"); const b = bnb.text("b"); const c = bnb.text("c"); const abc = a.or(b).or(c); abc.tryParse("a"); // => "a" abc.tryParse("b"); // => "b" abc.tryParse("c"); // => "c" ``` -------------------------------- ### Combining Parsers Sequentially with parser.and (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md The `parser.and(nextParser)` method creates a new parser that first runs the current parser, then runs `nextParser` immediately after. If both succeed, the new parser yields an array containing the results of both parsers. ```TypeScript const a = bnb.text("a"); const b = bnb.text("b"); const ab = a.and(b); ab.tryParse("a"); // => ["a", "b"] ``` -------------------------------- ### Creating Custom Parser (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md Shows how to create a new custom parser using the `new bnb.Parser()` constructor. The constructor takes an action function that receives a `Context` and returns an `ActionResult` indicating success or failure. ```TypeScript const number = new bnb.Parser((context) => { const start = context.location.index; const end = context.location.index + 2; if (context.input.slice(start, end) === "AA") { // Return how far we got, and what value we found return context.ok(end, "AA"); } // Return how far we got, and what value we were looking for return context.fail(start, ["AA"]); }); ``` -------------------------------- ### Combining Multiple Parsers Sequentially with Nested .chain (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/tutorial.md Illustrates how nested `.chain` calls can be used to parse a sequence of items and collect their results. Each inner `.chain` receives the result of the previous parser, and the final `.map` combines the results of all sequential parsers into a single output structure. ```TypeScript const oneChar = bnb.match(/./ms); const threeChars = oneChar.chain((first) => { return oneChar.chain((second) => { return oneChar.map((third) => { return [first, second, third]; }); }); }); threeChars.tryParse("abc"); // => ["a", "b", "c"] ``` -------------------------------- ### Conditional Parsing with .chain (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/tutorial.md Demonstrates using the `.chain` method to perform conditional parsing based on a previously parsed value. It parses an initial character, then uses its value (`first`) to dynamically create and return a new parser (`bnb.text(upper)`) for the subsequent input. The result combines the value of the first parser and the value of the returned parser. ```TypeScript const customString = bnb.match(/[a-z]/); const lowerUpperAlphaPair = lowerAlphaChar.chain((first) => { const upper = first.toUpperCase(); return bnb.text(upper); }); lowerUpperAlphaPair.tryParse("aA"); // => ["a", "A"] lowerUpperAlphaPair.tryParse("bB"); // => ["b", "B"] lowerUpperAlphaPair.tryParse("bb"); // => Error lowerUpperAlphaPair.tryParse("Aa"); // => Error ``` -------------------------------- ### Combining Parsers and Yielding First Result with parser.skip (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md The `parser.skip(nextParser)` method combines the current parser and `nextParser` sequentially. It runs the current parser, then `nextParser`, but only yields the result produced by the current parser. ```TypeScript const a = bnb.text("a"); const b = bnb.text("b"); const ab = a.skip(b); ab.tryParse("ab"); // => "a" ``` -------------------------------- ### Combining Parsers with Context.moveTo and Context.merge (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md Defines a parser function `multiply` that takes two other number parsers. It calls the first parser, moves the context forward on success, calls the second parser, merges results for error reporting using `context.merge()`, and finally returns a successful result using `context.ok()` after calculating the product. It depends on the `bnb` library and other parsers. ```typescript // NOTE: This is not the shortest way to write this parser, // it's just an example of a custom parser that needs to // call multiple other parsers. function multiply( parser1: bnb.Parser, parser2: bnb.Parser ): bnb.Parser { return new bnb.Parser((context) => { const result1 = parser1.action(context); if (result1.type === "ParseFail") { return result1; } context = context.moveTo(result1.location); const result2 = context.merge(result1, parser2.action(context)); if (result2.type === "ParseFail") { return result2; } context = context.moveTo(result2.location); const value = result1.value * result2.value; return context.merge(result2, context.ok(context.location.index, value)); }); } ``` -------------------------------- ### Creating Parser Node with Metadata (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md Demonstrates how to use `parser.node()` to attach a name and location metadata to a parsed value. Shows the structure of the resulting `ParseNode` object and provides TypeScript type aliases for common parsing results. ```TypeScript const identifier = bnb.match(/[a-z]+/i).node("Identifier"); identifier.tryParse("hello"); // => { // type: "ParseNode", // name: "Identifier", // value: "hello", // start: SourceLocation { index: 0, line: 1, column: 1 }, // end: SourceLocation { index: 5, line: 1, column: 6 } } // } // Create type aliases for TypeScript use type LispSymbol = bnb.ParseNode<"LispSymbol", string>; type LispNumber = bnb.ParseNode<"LispNumber", number>; type LispList = bnb.ParseNode<"LispList", LispExpr[]>; type LispExpr = LispSymbol | LispNumber | LispList; ``` -------------------------------- ### Combining Parsers and Yielding Second Result with parser.next (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md The `parser.next(nextParser)` method combines the current parser and `nextParser` sequentially. It runs the current parser, then `nextParser`, but only yields the result produced by `nextParser`. ```TypeScript const a = bnb.text("a"); const b = bnb.text("b"); const ab = a.next(b); ab.tryParse("ab"); // => "b" ``` -------------------------------- ### Capturing Source Location (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md Illustrates the use of the `bnb.location` parser to capture the current `SourceLocation` before and after another parser. Shows how to chain parsers together to build a result object containing the parsed value and its start/end locations. ```TypeScript const identifier = bnb.location.chain((start) => { return bnb.match(/[a-z]+/i).chain((name) => { return bnb.location.map((end) => { return { type: "Identifier", name, start, end }; }); }); }); identifier.tryParse("abc"); // => { // type: "Identifier", // name: "abc", // start: SourceLocation { index: 0, line: 1, column: 1 }, // end: SourceLocation { index: 2, line: 1, column: 3 } // } ``` -------------------------------- ### Creating Custom Parser with Context (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md Demonstrates how to define a custom parser using `new bnb.Parser()`. The parser function receives a `context` object, accesses the input string and location, checks the current character, and returns either `context.ok()` on success or `context.fail()` on failure. It depends on the `bnb` library. ```typescript const bracket = new bnb.Parser<"[" | "]">((context) => { const start = context.location.index; const end = start + 1; const ch = context.input.slice(start, end); if (ch === "[" || ch === "]") { return context.ok(end, ch); } return context.fail(start, ["[", "]"]); }); ``` -------------------------------- ### Parsing Structured Data with bnb.match, .map, and .sepBy (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/tutorial.md Illustrates using `bnb.match` to parse patterns defined by regular expressions, `.map` to transform the parsed string into a different data type (like a number or object), and `.sepBy` to parse one or more occurrences of a parser separated by another parser. This snippet shows how to build a complex parser for a version string and map it into a structured JavaScript object. ```ts const integer = bnb .match(/[0-9]+/) .map((str) => Number(str)) .desc(["integer"]); const version = integer .sepBy(bnb.text("."), 1) .map(([major, minor, patch]) => { return { major, minor, patch }; }) .desc(["version"]); version.tryParse("3.14.15"); // { major: 3, minor: 14, patch: 15 } ``` -------------------------------- ### Creating a Parser that Succeeds Immediately with bnb.ok (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md The `bnb.ok(value)` function returns a parser that yields the specified `value` without consuming any input. It is commonly used as a fallback option in parser combinations where parsing nothing is acceptable. ```TypeScript const sign = bnb.text("+").or(bnb.text("-")).or(bnb.ok("")); sign.tryParse("+"); // => "+" sign.tryParse("-"); // => "-" sign.tryParse(""); // => "" ``` -------------------------------- ### Sequencing Parsers Based on Previous Result with parser.chain (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md The `parser.chain(callback)` method runs the current parser and, if successful, passes its result to the provided `callback` function. The `callback` must return the next parser to be executed, allowing for dynamic parser sequencing based on previously parsed values. ```TypeScript const balance = bnb.choice(bnb.text("("), bnb.text("[")).chain((first) => { if (first === "(") { return bnb.text(")").map((last) => [first, last]); } else { return bnb.text("]").map((last) => [first, last]); } }); balance.tryParse("()"); // => ["(", ")"] balance.tryParse("[]"); // => "[", "]"] ``` -------------------------------- ### Transforming bnb.all Results with .map and Destructuring (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/tutorial.md Demonstrates applying the `.map` method to the result of `bnb.all` to transform the output structure. It uses array destructuring on the array result from `bnb.all` to easily access individual parsed values and restructure them into a new object. ```TypeScript const oneChar = bnb.match(/./ms); const threeChars = bnb.all(oneChar, oneChar, oneChar).map(([c1, ct, c3]) => { return { c1, c2: ct, c3 }; }); threeChars.tryParse("abc"); // => { // c1: "a", // c2: "b", // c3: "c", // } ``` -------------------------------- ### Trying Alternative Parsers with parser.or (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md The `parser.or(otherParser)` method creates a new parser that first attempts to parse using the current parser. If the current parser fails, it then attempts to parse using `otherParser`. It yields the result of the first parser that succeeds. ```TypeScript const a = bnb.text("a"); const b = bnb.text("b"); const ab = a.or(b); ab.tryParse("a"); // => "a" ab.tryParse("b"); // => "b" // You can also use this to implement optional parsers const aMaybe = bnb.text("a").or(bnb.ok(null)); aMaybe.tryParse("a"); // => "a" aMaybe.tryParse(""); // => null ``` -------------------------------- ### Using parser.sepBy in TypeScript Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md Returns a parser that parses the current parser a specified number of times (min to max), with each instance separated by 'sepParser'. The results are collected into an array. ```ts const num = bnb.match(/[0-9]+/).map(Number); const color = bnb .text("rgb(") .next(num.sepBy(bnb.text(","), 1)) .skip(bnb.text(")")) .map(([red, green, blue]) => { return { red, green, blue }; }); color.tryParse("rgb(0,127,36)"); // => { red: 0, green: 127, blue: 36 } const classNames = bnb.match(/\S+/).sepBy(bnb.match(/\s+/)); classNames.tryParse(""); // => [] classNames.tryParse("btn"); // => ["btn"] classNames.tryParse("btn btn-primary"); // => ["btn", "btn-primary"] const dimensions = bnb .match(/\d+/) .map((str) => Number(str)) .sepBy(bnb.match(/\s*x\s*/), 2, 3); classNames.tryParse(""); // => Error classNames.tryParse("3 x 4"); // => [3, 4] classNames.tryParse("10x20x30"); // => [10, 20, 30] classNames.tryParse("1x2x3x4"); // => Error ``` -------------------------------- ### Applying Function via thru (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md Illustrates the use of the `parser.thru()` method to apply a function to a parser within a method chain. Compares chaining with `thru` to applying the function directly to demonstrate equivalence. ```TypeScript function paren(parser) { return parser.wrap(bnb.text("("), bnb.text(")")); } const paren1 = bnb.text("a").thru(paren).desc(["(a)"]); // --- vs --- const paren2 = paren(bnb.text("a")).desc(["(a)"]); paren1.tryParse("(a)"); // => "a" paren2.tryParse("(a)"); // => "a" ``` -------------------------------- ### Performing Assertions with .chain, bnb.ok, and bnb.fail (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/tutorial.md Shows how to use `.chain` to validate a parsed value after it has been obtained. The callback function receives the parsed value (`num`) and can return `bnb.fail` with an error message if a condition is not met, or `bnb.ok` with the value if it is valid. ```TypeScript const number = bnb .match(/[0-9]+/) .map(Number) .chain((num) => { if (num === 420) { return bnb.fail(["appropriate number"]); } return bnb.ok(num); }); ``` -------------------------------- ### Using parser.wrap in TypeScript Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md Returns a parser that sequences 'beforeParser', the current parser, and 'afterParser', yielding only the value from the current parser. This is useful for adding delimiters like brackets around a parser's output. ```ts const item = bnb.text("a"); const comma = bnb.text(","); const lbrack = bnb.text("["); const rbrack = bnb.text("]"); const list = item.sepBy(comma).wrap(lbrack, rbrack); list.tryParse("[a,a,a]"); // => ["a", "a", "a"] ``` -------------------------------- ### Handling End-of-File with bnb.eof (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md Demonstrates how to use the `bnb.eof` parser to handle the end of input. Shows combining it with a newline parser (`match(/\r?\n/)`) using `.or()` to correctly parse statements terminated by either a newline or the end of the file. ```TypeScript const endline = bnb.match(/\r?\n/).or(bnb.eof); const statement = bnb .match(/[a-z]+/i) .and(endline) .map(([first]) => first); const file = statement.repeat(); file.tryParse("A\nB\nC"); // => ["A", "B", "C"] ``` -------------------------------- ### Using parser.repeat in TypeScript Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md Repeats the current parser a specified number of times (min to max), collecting the results into an array. The default range is 0 to Infinity. Caution is advised when the minimum is 0, as it can match an empty sequence. ```ts const identifier = bnb.match(/[a-z]+/i); const expression = identifier.and(bnb.text("()")).map(([first]) => first); const statement = expression.and(bnb.text(";")).map(([first]) => first); const block = statement.repeat().wrap(bnb.text("{"), bnb.text("}")); block.tryParse("{apple();banana();coconut();}"); // => ["apple", "banana", "coconut"]; const aaa = bnb.text("a").repeat(1, 3); aaa.tryParse(""); // => Error aaa.tryParse("a"); // => "a" aaa.tryParse("aa"); // => "aa" aaa.tryParse("aaa"); // => "aaa" aaa.tryParse("aaaa"); // => Error const xs = bnb.text("x").repeat(1); xs.tryParse(""); // => Error xs.tryParse("x"); // => "x" xs.tryParse("xx"); // => "xx" ``` -------------------------------- ### Parsing Entire Input with parser.parse (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md The `parser.parse(input)` method attempts to parse the entire input string. It returns a `ParseResult` object, which can be either `ParseOK` (containing the value) or a failure object with location and expected values. This method requires the parser to consume the entire input to succeed. ```TypeScript const a = bnb.text("a"); const result1 = a.parse("a"); if (result.type === "ParseOK") { console.log(result.value); // => "a" } else { const { location, expected } = result; console.error("error at line", location.line, "column", location.column); console.error("expected one of", expected.join(", ")); } ``` -------------------------------- ### Handling Recursive Grammars with bnb.lazy (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/tutorial.md Shows how to use `bnb.lazy` to define parsers that are recursive or mutually recursive, which is essential for parsing nested structures like arrays containing expressions that can themselves be arrays. `bnb.lazy` delays the evaluation of the parser definition until it's needed, preventing circular dependency errors during parser construction. ```TypeScript // We have to use lazy here because `number` and `array` aren't defined yet const expression = bnb.lazy(() => { return number.or(array); // NOTE: You can use bnb.choice(...parsers) if you have several parsers }); const number = bnb.match(/[0-9]+/).map(Number); // `array` is indirectly recursive because it uses `expression` which // internally uses `array` const array = expression .sepBy(bnb.text(" ")) .wrap(bnb.text("("), bnb.text(")")); expression.tryParse("12"); // => 12 expression.tryParse("()"); // => [] expression.tryParse("(())"); // => [[]] expression.tryParse("((1 2) (3 4))"); // => [[1, 2], [3, 4]] ``` -------------------------------- ### Creating a Parser that Fails with bnb.fail (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md The `bnb.fail(expected)` function returns a parser that immediately fails with a given array of `expected` string messages, consuming no input. It's typically used within conditional logic (like in a `chain` callback) to signal a specific type of parsing failure. ```TypeScript const number = bnb.match(/[0-9]+/).chain((s) => { const n = Number(s); if (Number.isFinite(n)) { return bnb.ok(n); } else { return bnb.fail(["smaller number"]); } }); number.tryParse("1984"); // => 1984 number.tryParse("9".repeat(999)); // => error: expected smaller number ``` -------------------------------- ### Using parser.trim in TypeScript Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md Returns a parser that sequences 'trimParser', the current parser, and 'trimParser' again, yielding only the value from the current parser. This is commonly used with parsers that handle optional whitespace or comments. ```ts const whitespace = bnb.match(/\s+/); const optWhitespace = whitespace.or(bnb.ok("")); const item = bnb.text("a").trim(optWhitespace); item.tryParse(" a "); // => "a" ``` -------------------------------- ### Transforming Parser Results with parser.map (TypeScript) Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md The `parser.map(callback)` method applies a transformation function (`callback`) to the result of the parser. The value returned by the `callback` becomes the new result of the parser, allowing you to convert parsed strings to numbers, booleans, or other data structures. ```TypeScript const num = bnb.match(/[0-9]+/).map((str) => Number(str)); num.tryParse("1312"); // => 1312 num.tryParse("777"); // => 777 const yes = bnb.text("yes").map(() => true); const no = bnb.text("no").map(() => false); const bool = yes.or(no); bool.tryParse("yes"); // => true bool.tryParse("no"); // => false ``` -------------------------------- ### Using parser.desc in TypeScript Source: https://github.com/wavebeem/bread-n-butter/blob/main/docs/api.md Returns a parser that discards original error messages and uses the supplied 'expected' messages instead. This is typically used on token parsers (like strings or numbers) after regex parsers to provide clearer error output. ```ts const jsonNumber1 = bnb .match(/-?(0|[1-9][0-9]*)([.][0-9]+)?([eE][+-]?[0-9]+)?/) .map(Number); const jsonNumber2 = jsonNumber1.desc(["number"]); jsonNumber1.tryParse("x"); // => ["/-?(0|[1-9][0-9]*)([.][0-9]+)?([eE][+-]?[0-9]+)?/"] jsonNumber2.tryParse("x"); // => ["number"] ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.