{"id":18364166,"url":"https://github.com/boxbeam/untwine","last_synced_at":"2025-04-08T03:13:02.524Z","repository":{"id":219001046,"uuid":"747841172","full_name":"boxbeam/untwine","owner":"boxbeam","description":"The prettier pattern-matching parser with automatic error recovery","archived":false,"fork":false,"pushed_at":"2024-05-27T21:55:28.000Z","size":362,"stargazers_count":110,"open_issues_count":0,"forks_count":4,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-05-30T13:41:40.116Z","etag":null,"topics":["parser-generator","parsing"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/boxbeam.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-01-24T18:41:55.000Z","updated_at":"2024-06-13T06:24:57.865Z","dependencies_parsed_at":"2024-04-20T04:27:33.150Z","dependency_job_id":"41c412f6-eb56-4a04-9ffa-357895331147","html_url":"https://github.com/boxbeam/untwine","commit_stats":null,"previous_names":["boxbeam/untwine"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boxbeam%2Funtwine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boxbeam%2Funtwine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boxbeam%2Funtwine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boxbeam%2Funtwine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/boxbeam","download_url":"https://codeload.github.com/boxbeam/untwine/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247767236,"owners_count":20992548,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["parser-generator","parsing"],"created_at":"2024-11-05T23:09:30.564Z","updated_at":"2025-04-08T03:13:02.499Z","avatar_url":"https://github.com/boxbeam.png","language":"Rust","readme":"# Untwine\n\nThe prettier pattern-matching parser with automatic error recovery\n\n![Example expression errors](./screenshots/json-3.png)\n\nUntwine is a declarative parsing library which allows a style of parsing which is similar to direct pattern matching using a custom macro syntax.\nThis allows the creation of extremely compact parsers with decent performance characteristics and high-quality error messages.\nThese parsers are simple to implement, with a couple cherry-picked examples being:\n- A nearly-complete JSON parser in 12 lines of parsing logic\n  - Supports all basic JSON functionality except for special escape sequences (those other than \\\\\")\n- A pmdas-respecting four-operation expression parser in 6 lines of parsing logic\n  - And one helper function to operate on two numbers\n\nParsers made using untwine also have high-quality error messages visually displaying the error and relevant syntax.\n\n## Usage\n\nThis readme will mostly cover examples and features. For a usage breakdown, see https://docs.rs/untwine/latest/untwine/macro.parser.html.\n\nFor a more guided tutorial, see https://github.com/boxbeam/untwine/blob/master/TUTORIAL.md\n\n## Simple, declarative parsing\n\nUntwine allows you to parse by simply describing the syntax you want to parse, and selecting the parts of the output you want.\nBelow is the code implementing an expression parser in Untwine.\n\n```rust\nfn operate(left: f64, op: char, right: f64) -\u003e f64 {\n    match op {\n        '+' =\u003e left + right,\n        '-' =\u003e left - right,\n        '/' =\u003e left / right,\n        '*' =\u003e left * right,\n        _ =\u003e unreachable!(),\n    }\n}\n\nparser! {\n    sep = #{char::is_ascii_whitespace}*;\n    num: num=\u003c\"-\"? '0'-'9'+ (\".\" '0'-'9'+)?\u003e -\u003e f64 { num.parse().unwrap() }\n    term = (num | \"(\" sep expr sep \")\") -\u003e f64;\n    add: first=mul sep ops=([\"+-\"] sep mul)* -\u003e f64 { ops.into_iter().fold(first, |left, (op, right)| operate(left, op, right)) }\n    mul: first=term sep ops=([\"*/\"] sep term)* -\u003e f64 { ops.into_iter().fold(first, |left, (op, right)| operate(left, op, right)) }\n    pub expr = add -\u003e f64;\n}\n```\n\nWhile this guide will not seek to fully explain the parser, there are several key features on show.\nFirst, the syntax is somewhat similar to Regex or EBNF. Each parser declares the pattern it is matching\nagainst, and may use `name=` in front of any top-level pattern to extract the value of that pattern\ninto a variable. Once the structure is matched, you evaluate the output of the parser in a code block.\n\nThe benefit of this approach is leveraging the power of a formal grammar while still allowing full\nintegration with the type system and IDE insight.\n\nIn addition to sheer brevity, the parsers boast colorful errors generated automatically from the syntax\nyou described, and will effectively illustrate any syntax errors.\n\n## Errors\n\nHere I will showcase some of the errors generated by both the expression parser and the JSON parser. These\nwere obtained through the example REPLs, which can be run with `cargo run --example expr` and `cargo run --example json`\nrespectively.\n\n![Example expression errors](./screenshots/expr-1.png)\n\nUntwine supports automatic error recovery, enabling the same 12 lines of code to continue parsing after an error to\ndiscover more errors. A recovered input with error nodes can also be obtained.\n![Example json errors](./screenshots/json-1.png)\n\nSince errors indicate a range rather than just a single position, multiline errors are also supported:\n\n![Example multiline JSON errors](./screenshots/json-2.png)\n\nTo see the full implementation of both of these parsers, see [examples/json.rs](https://github.com/boxbeam/untwine/blob/master/examples/json.rs)\nand [examples/expr.rs](https://github.com/boxbeam/untwine/blob/master/examples/json.rs)\n\n## Performance and goals\n\nWhile Untwine currently has no formal benchmarks, informally I have found parsers written using Untwine to be about\ntwo-thirds as fast as a basic but well-optimized handwritten parser. While Untwine seeks to offer high performance,\nit is not suitable for highly performance-critical parsers.\n\nMost parsing is not so performance-critical, and Untwine is ideal for building programming languages or DSLs,\nwhere high-quality error messages are more important. It seeks to make parsing so easy that it becomes worthwhile to\nwrite parsers where it may not have been before, giving you the ability to iterate extremely quickly and eliminate\nmost of the pain points of manual parsing.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboxbeam%2Funtwine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fboxbeam%2Funtwine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboxbeam%2Funtwine/lists"}