{"id":20052770,"url":"https://github.com/ryosukecla/parser-combinator-rs","last_synced_at":"2026-05-06T16:07:08.730Z","repository":{"id":148437419,"uuid":"163027398","full_name":"RyosukeCla/parser-combinator-rs","owner":"RyosukeCla","description":"parser combinator - rust implementation","archived":false,"fork":false,"pushed_at":"2019-02-22T08:54:27.000Z","size":97,"stargazers_count":1,"open_issues_count":2,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-05-26T04:10:52.662Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/RyosukeCla.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2018-12-24T22:38:50.000Z","updated_at":"2018-12-28T17:36:43.000Z","dependencies_parsed_at":"2023-09-11T20:22:35.288Z","dependency_job_id":null,"html_url":"https://github.com/RyosukeCla/parser-combinator-rs","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/RyosukeCla/parser-combinator-rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RyosukeCla%2Fparser-combinator-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RyosukeCla%2Fparser-combinator-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RyosukeCla%2Fparser-combinator-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RyosukeCla%2Fparser-combinator-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RyosukeCla","download_url":"https://codeload.github.com/RyosukeCla/parser-combinator-rs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RyosukeCla%2Fparser-combinator-rs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32701417,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-06T08:33:17.875Z","status":"ssl_error","status_checked_at":"2026-05-06T08:33:17.221Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2024-11-13T12:19:10.785Z","updated_at":"2026-05-06T16:07:08.726Z","avatar_url":"https://github.com/RyosukeCla.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Parser Combinator - rust implementation\n\nUnder construction..\n\n## Examples\n\n### Expression\n\n```rust\nuse crate::parser::{\n  char, choice, extract_map, flatten_map, kind, lazy, many, map, regexp, seq, token, trim,\n  type_map, wrap_map, Node, ParserCombinator, Type,\n};\n\nfn main() {\n  let space = token(\" \");\n  let num = kind(\n    \u0026type_map::\u003c_, _, i32\u003e(\u0026trim(\u0026regexp(r\"([1-9][0-9]*|[0-9])\"), \u0026space)),\n    \"Num\",\n  );\n  let operator = kind(\u0026char(\"+-*/\"), \"Op\");\n  let parenthesis = lazy();\n  let atom = choice(\u0026num).or(\u0026parenthesis);\n  let expression = kind(\n    \u0026flatten_map(\u0026seq(\u0026wrap_map(\u0026atom)).and(\u0026flatten_map(\u0026many(\u0026seq(\u0026operator).and(\u0026atom))))),\n    \"Expr\",\n  );\n  let paren_open = trim(\u0026token(\"(\"), \u0026space);\n  let paren_close = trim(\u0026token(\")\"), \u0026space);\n\n  parenthesis.set_parser(\u0026extract_map(\n    \u0026seq(\u0026paren_open).and(\u0026expression).and(\u0026paren_close),\n    1, // extract expression\n  ));\n\n  let parser: ParserCombinator = ParserCombinator::new(\u0026expression);\n  let target = \"1 + 2 - (3 * 4) / (5)\";\n  println!(\"[In]:\\n{}\\n\", target);\n  println!(\"[Out]:\\n{}\\n\", parser.parse(target).unwrap()); // simple print\n}\n```\n\n```\n[In]:\n1 + 2 - (3 * 4) / (5)\n\n[Out]:\nExpr [Num I32(1), Op Str(\"+\"), Num I32(2), Op Str(\"-\"), Expr [Num I32(3), Op Str(\"*\"), Num I32(4)], Op Str(\"/\"), Expr [Num I32(5)]]\n```\n\n### Complex Number\n\n```rust\nuse crate::parser::{\n  map, regexp, seq, token, type_map, Node, ParserCombinator, Type,\n};\n\n#[derive(Clone, Debug)]\nenum ExtendedType {\n  Complex32(i32, i32),\n}\n\nfn main() {\n  let num = type_map::\u003c_, _, i32\u003e(\u0026regexp(r\"([1-9][0-9]*|[0-9])\"));\n  let plus = token(\"+\");\n  let imaginary = token(\"i\");\n  let expr = seq(\u0026num).and(\u0026plus).and(\u0026num).and(\u0026imaginary);\n  let complex = map(\n    \u0026expr,\n    Box::new(|node| match node.value {\n      Type::Arr(children) =\u003e {\n        let re = match children[0].value {\n          Type::I32(re) =\u003e re,\n          _ =\u003e panic!(\"err\"),\n        };\n        let im = match children[2].value {\n          Type::I32(re) =\u003e re,\n          _ =\u003e panic!(\"err\"),\n        };\n\n        Node {\n          value: Type::Val(ExtendedType::Complex32(re, im)),\n          kind: None,\n        }\n      }\n      _ =\u003e panic!(\"Error\"),\n    }),\n  );\n\n  let parser: ParserCombinator\u003cExtendedType\u003e = ParserCombinator::new(\u0026complex);\n\n  let target = \"100+100i\";\n  println!(\"[In]:\\n{}\\n\", target);\n  println!(\"[Out]:\\n{:#?}\\n\", parser.parse(target).unwrap()); // detail print\n}\n```\n\n```\n[In]:\n100+100i\n\n[Out]:\nNode {\n    value: Val(\n        Complex32(\n            100,\n            100\n        )\n    ),\n    kind: None\n}\n```\n\n## Basic\n\n### parse\n\n```rust\nuse crate::parser::{parse, DefaultType};\nlet parser = // ...\nlet target = \"target \u0026str\";\nparse::\u003cDefaultType, _\u003e(\u0026parser, target); // -\u003e Result\u003cNode, String\u003e\n```\n\nor\n\n```rust\nuse crate::parser::ParserCombinator;\nlet parser = // ...\nlet parser = ParserCombinator::new(\u0026parser);\nlet target = \"target \u0026str\";\nparser.parse(target); // -\u003e Result\u003cNode, String\u003e\n```\n\n### custom type\n\nCustomize parsed data type.\n\n```rust\nuse crate::parser::ParserCombinator;\n\n#[derive(Clone, Debug)]\nenum ExtendedType {\n  ComplexI32(i32, i32),\n}\n\nlet parser = // ...\nlet parser: ParserCombinator\u003cExtendedType\u003e = ParserCombinator::new(\u0026parser);\n```\n\n### Struct and Trait\n\n```rust\n#[derive(Debug, Clone)]\npub struct State\u003cT: Clone\u003e {\n  pub success: bool,\n  pub node: Option\u003cNode\u003cT\u003e\u003e,\n  pub position: usize,\n}\n\n#[derive(Debug, Clone)]\npub struct Node\u003cT: Clone\u003e {\n  pub value: Type\u003cT\u003e,\n  pub kind: Option\u003cString\u003e,\n}\n\n#[derive(Clone, Debug)]\npub enum Type\u003cT: Clone\u003e {\n  Str(String),\n  Char(char),\n  Isize(isize),\n  Usize(usize),\n  U8(u8),\n  U16(u16),\n  U32(u32),\n  U64(u64),\n  U128(u128),\n  I16(i16),\n  I32(i32),\n  I64(i64),\n  I128(i128),\n  F32(f32),\n  F64(f64),\n  Bool(bool),\n  Val(T),\n  Arr(Vec\u003cNode\u003cT\u003e\u003e),\n}\n\npub trait Parser\u003cT: Clone\u003e {\n  fn parse(\u0026self, target: \u0026str, position: usize) -\u003e State\u003cT\u003e;\n  fn box_clone(\u0026self) -\u003e Box\u003cParser\u003cT\u003e\u003e;\n}\n```\n\n## Combinators\n\n### Kind\n\nGrant label\n\n```rust\nlet num = kind(\u0026RegExp(r\"([1-9][0-9]*|[0-9])\"), \"Num\");\nprintln!(\"{}\", parse(\u0026num, \"100\").unwrap());\n// Num 100\n```\n\n### Token\n\n```rust\nlet token = token(\"token\");\nprintln!(\"{}\", parse(\u0026token, \"token\").unwrap());\n// token\n```\n\n### Char\n\n```rust\nlet operator = char(\"+-\");\nprintln!(\"{}\", parse(\u0026operator, \"+\").unwrap());\n// +\nprintln!(\"{}\", parse(\u0026operator, \"-\").unwrap());\n// -\n```\n\n### Regex\n\n```rust\nlet num = regexp(r\"([1-9][0-9]*|[0-9])\");\nprintln!(\"{}\", parse(\u0026number, \"12345\").unwrap());\n// 12345\n```\n\n### Sequence\n\n```rust\nlet seq = seq(\u0026token(\"a\")).and(\u0026token(\"b\"));\nprintln!(\"{}\", parse(\u0026seq, \"ab\").unwrap());\n// [a, b]\n```\n\n### Many\n\n```rust\nlet many = many(\u0026token(\"a\"));\nprintln!(\"{}\", parse(\u0026many, \"aaaaa\").unwrap());\n// [a, a, a, a, a]\n```\n\n### Option\n\n```js\n/(option)?/;\n```\n\n```rust\nlet option = opt(\u0026token(\"aaa\"));\nprintln!(\"{}\", parse(\u0026option, \"aaa\").unwrap());\n// aaa\nprintln!(\"{}\", parse(\u0026option, \"\").unwrap());\n//\n```\n\n### Choice\n\n```rust\nlet choice = choice(\u0026token(\"a\")).or(\u0026token(\"b\"));\nprintln!(\"{}\", parse(\u0026choice, \"a\").unwrap());\n// a\nprintln!(\"{}\", parse(\u0026choice, \"b\").unwrap());\n// b\n```\n\n### Lazy\n\nLazy initialized parser.\nIt is useful for making recursive parser.\n\n```rust\nlet lazy = lazy();\n// define parsers\nlazy.set_parser(\u0026parser);\n```\n\n### Filter\n\n```rust\nlet f = |node| =\u003e true\nlet filtered = filter(\u0026parser, f);\n```\n\n### Map\n\nmap node to new node.\n\n```rust\n// map a to b\nlet map = map(\n  \u0026token(\"a\"),\n  |node| {\n    Node {\n      value: Type::Str(\"b\".to_string()),\n      kind: None,\n    }\n  }\n);\nprintln!(\"{}\", parse(\u0026map, \"a\").unwrap());\n// b\n```\n\n### Type Map\n\nmap str to specific type.\n\n```\nTypeMap(Type::Str) =\u003e Type::I32\n```\n\n```rust\nlet toI32 = type_map::\u003c_, _, i32\u003e(\u0026parser);\nlet toI64 = type_map::\u003c_, _, i64\u003e(\u0026parser);\n```\n\n### Extract\n\nExtract an element from elements.\n\n```\nExtractMap([ a, b, c ], 1) = b\n```\n\n```rust\nlet extraction = extract(\u0026parser, extraction_index);\n```\n\n### Flatten\n\nFlatten elements in elements.\n\n```\nFlatten(\n  [\n    [a1, b1, c1, ...],\n    [a2, b2, c2, ...]\n  ]\n) = [a1, b1, c1, ..., a2, b2, c2, ...]\n```\n\n```rust\nlet flatten = flatten(\u0026parser);\n```\n\n### Wrap Map\n\nWrap elements.\n\n```\nWrapMap([a, b, c, ...]) = [[a, b, c, ...]]\n```\n\n```rust\nlet wrap = wrap(\u0026parser);\n```\n\n### Unwrap\n\nUnwrap element.\n\n```\nWrapMap([a]) = a\n```\n\n```rust\nlet unwrap = unwrap(\u0026parser);\n```\n\n### Trim\n\nTriming \"a\" by \"-\" yields: \"--a--\" -\u003e \"a\"\n\n```rust\nlet trim = trim(\u0026parser, \u0026by);\n\n// eg\nlet trim = trim(\u0026token(\"a\"), \u0026token(\"-\"));\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fryosukecla%2Fparser-combinator-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fryosukecla%2Fparser-combinator-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fryosukecla%2Fparser-combinator-rs/lists"}