{"id":13416042,"url":"https://github.com/kareman/FootlessParser","last_synced_at":"2025-03-14T23:31:16.052Z","repository":{"id":30322399,"uuid":"33874667","full_name":"kareman/FootlessParser","owner":"kareman","description":"A simple parser combinator written in Swift","archived":false,"fork":false,"pushed_at":"2024-04-28T14:56:44.000Z","size":2372,"stargazers_count":63,"open_issues_count":2,"forks_count":9,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-10-13T21:34:26.395Z","etag":null,"topics":["parser-combinators","swift","swift-library"],"latest_commit_sha":null,"homepage":null,"language":"Swift","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/kareman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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":"2015-04-13T14:53:16.000Z","updated_at":"2023-11-04T17:30:24.000Z","dependencies_parsed_at":"2022-09-07T01:00:50.426Z","dependency_job_id":null,"html_url":"https://github.com/kareman/FootlessParser","commit_stats":{"total_commits":201,"total_committers":7,"mean_commits":"28.714285714285715","dds":"0.14925373134328357","last_synced_commit":"11c7a366720a2cc62d13ee69c8bdb8372bb3bb2b"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kareman%2FFootlessParser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kareman%2FFootlessParser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kareman%2FFootlessParser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kareman%2FFootlessParser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kareman","download_url":"https://codeload.github.com/kareman/FootlessParser/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243663478,"owners_count":20327299,"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-combinators","swift","swift-library"],"created_at":"2024-07-30T21:00:53.865Z","updated_at":"2025-03-14T23:31:15.526Z","avatar_url":"https://github.com/kareman.png","language":"Swift","readme":"[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n\nSwift 5, 4.2 and 4.1 | [Swift 2.2+](https://github.com/kareman/FootlessParser/tree/swift2.2%2B)\n\n# FootlessParser\n\nFootlessParser is a simple and pretty naive implementation of a parser combinator in Swift. It enables infinite lookahead, non-ambiguous parsing with error reporting.\n\nThere is [a series of blog posts about the development](https://nottoobadsoftware.com/blog/footlessparser/) and [documentation from the source code](https://kareman.github.io/FootlessParser/).\n\n## Introduction\n\nIn short, FootlessParser lets you define parsers like this:\n\n```swift\nlet parser = function1 \u003c^\u003e parser1 \u003c*\u003e parser2 \u003c|\u003e parser3\n```\n\n`function1` and `parser3` return the same type.\n\n`parser` will pass the input to `parser1` followed by `parser2`, pass their results to `function1` and return its result. If that fails it will pass the original input to `parser3` and return its result.\n\n## Definitions\n\n### Parser\n\nA function which takes some input (a sequence of tokens) and returns either the output and the remaining unparsed part of the input, or an error description if it fails.\n\n### Token\n\nA single item from the input. Like a character from a string, an element from an array or a string from a list of command line arguments.\n\n### Parser Input\n\nMost often text, but can also be an array or really any collection of anything, provided it conforms to CollectionType.\n\n## Parsers\n\nThe general idea is to combine very simple parsers into more complex ones. So `char(\"a\")` creates a parser which checks if the next token from the input is an \"a\". If it is it returns that \"a\", otherwise it returns an error. You can then use operators and functions like `zeroOrMore` and `optional` to create ever more complex parsers. For more check out [the full list of functions](https://kareman.github.io/FootlessParser/Functions.html).\n\n## Operators\n\n#### \u003c^\u003e (map)\n\n`function \u003c^\u003e parser1` creates a new parser which runs parser1\\. If it succeeds it passes the output to `function` and returns the result.\n\n#### \u003c*\u003e (apply)\n\n`function \u003c^\u003e parser1 \u003c*\u003e parser2` creates a new parser which first runs parser1\\. If it succeeds it runs parser2\\. If that also succeeds it passes both outputs to `function` and returns the result.\n\nThe \u003c*\u003e operator requires its left parser to return a function and is normally used together with \u003c^\u003e. `function` must take 2 parameters of the correct types, and it must be curried, like this:\n\n```swift\nfunc function (a: A) -\u003e (B) -\u003e C\n```\n\nThis is because \u003c*\u003e returns the output of 2 parsers and it doesn't know what to do with them. If you want them returned in a tuple, an array or e.g. added together you can do so in the function before \u003c^\u003e .\n\nIf there are 3 parsers and 2 \u003c*\u003e the function must take 3 parameters, and so on.\n\n#### \u003c*\n\nThe same as the \u003c*\u003e above, except it discards the result of the parser to its right. Since it only returns one output it doesn't need to be used together with \u003c^\u003e . But you can of course if you want the output converted to something else.\n\n#### *\u003e\n\nThe same as \u003c* , but discards the result of the parser to its left.\n\n#### \u003c|\u003e (choice)\n\n```\nparser1 \u003c|\u003e parser2 \u003c|\u003e parser3\n```\n\nThis operator tries all the parsers in order and returns the result of the first one that succeeds.\n\n#### \u003e\u003e- (flatmap)\n\n```\nparser1 \u003e\u003e- ( o -\u003e parser2 )\n```\n\nThis does the same as the flatmap functions in the Swift Standard Library. It creates a new parser which first tries parser1\\. If it fails it returns the error, if it succeeds it passes the output to the function which uses it to create parser2\\. It then runs parser2 and returns its output or error.\n\n## Example\n\n### Real life usage\n\n- [oleander/BitBarParser](https://github.com/oleander/BitBarParser/blob/master/Parser/Parser/Parser.swift) - lets you put the output from any script/program in your Mac OS X Menu Bar.\n- [banjun/NorthLayout](https://github.com/banjun/NorthLayout/blob/master/Classes/VFLSyntax.swift) - autolayout views in code.\n\n### [CSV](https://www.computerhope.com/jargon/c/csv.htm) parser\n\n```swift\nlet delimiter = \",\" as Character\nlet quote = \"\\\"\" as Character\nlet newline = \"\\n\" as Character\n\nlet cell = char(quote) *\u003e zeroOrMore(not(quote)) \u003c* char(quote)\n\t\u003c|\u003e zeroOrMore(noneOf([delimiter, newline]))\n\nlet row = extend \u003c^\u003e cell \u003c*\u003e zeroOrMore(char(delimiter) *\u003e cell) \u003c* char(newline)\nlet csvparser = zeroOrMore(row)\n```\n\nHere a cell (or field) either:\n\n- begins with a \", then contains anything, including commas, tabs and newlines, and ends with a \" (both quotes are discarded)\n- or is unquoted and contains anything but a comma or a newline.\n\nEach row then consists of one or more cells, separated by commas and ended by a newline. The `extend` function joins the cells together into an array. Finally the `csvparser` collects zero or more rows into an array.\n\nTo perform the actual parsing:\n\n```swift\ndo {\n    let output = try parse(csvparser, csvtext)\n    // output is an array of all the rows,\n    // where each row is an array of all its cells.\n} catch {\n\n}\n```\n\n### Recursive expression\n\n```swift\nfunc add(a: Int) -\u003e (Int) -\u003e Int { return { b in a + b } }\nfunc multiply(a: Int) -\u003e (Int) -\u003e Int { return { b in a + b } }\n\nlet nr = { Int($0)! } \u003c^\u003e oneOrMore(oneOf(\"0123456789\"))\n\nvar expression: Parser\u003cCharacter, Int\u003e!\n\nlet factor = nr \u003c|\u003e lazy (char(\"(\") *\u003e expression \u003c* char(\")\"))\n\nvar term: Parser\u003cCharacter, Int\u003e!\nterm = lazy (multiply \u003c^\u003e factor \u003c* char(\"*\") \u003c*\u003e term \u003c|\u003e factor)\n\nexpression = lazy (add \u003c^\u003e term \u003c* char(\"+\") \u003c*\u003e expression \u003c|\u003e term)\n\ndo {\n\tlet result = try parse(expression, \"(1+(2+4))+3\")\n} catch {\n\n}\n```\n\n`expression` parses input like `\"12\"`, `\"1+2+3\"`, `\"(1+2)\"`, `\"12*3+1\"` and `\"12*(3+1)\"` and returns the result as an Int.\n\nAll parsers which refer to themselves directly or indirectly must be pre-declared as variable implicitly unwrapped optionals (`var expression: Parser\u003cCharacter, Int\u003e!`). And to avoid infinte recursion the definitions must use the `lazy` function.\n\n## Installation\n\n### Using [Carthage](https://github.com/Carthage/Carthage)\n\n```\ngithub \"kareman/FootlessParser\"\n```\n\nThen run `carthage update`.\n\nThen follow the installation instructions in [Carthage's README][carthage-installation].\n\n### Using [CocoaPods](https://cocoapods.org/)\n\nAdd `FootlessParser` to your `Podfile` file.\n\n```\npod 'FootlessParser', '~\u003e 0.5.2'\n```\n\nThen run `pod install` to install it.\n\n[carthage-installation]: https://github.com/Carthage/Carthage#adding-frameworks-to-an-application\n","funding_links":[],"categories":["Swift"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkareman%2FFootlessParser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkareman%2FFootlessParser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkareman%2FFootlessParser/lists"}