robrix / Madness

Recursive Descent Into Madness
MIT License
291 stars 17 forks source link

Recursive Descent into Madness

Madness is a Swift µframework for parsing strings in simple context-free grammars. Combine parsers from simple Swift expressions and parse away:

let digit = %("0"..."9") <|> %("a"..."f") <|> %("A"..."F")
let hex = digit+ |> map { strtol(join("", $0), nil, 16) }
parse(%"0x" *> hex, "0xdeadbeef") // => 3,735,928,559

Your parsers can produce your own model objects directly, making Madness ideal for experimenting with grammars, for example in a playground.

screenshot of parsing HTML colours in an Xcode playground: `let reddish = parse(colour, "#d52a41")!`

See Madness.playground for some examples of parsing with Madness.

Use

API documentation is in the source.

This way Madness lies

∞ loop de loops

Madness employs simple—naïve, even—recursive descent parsing. Among other things, that means that it can’t parse any arbitrary grammar that you could construct with it. In particular, it can’t parse left-recursive grammars:

let number = %("0"..."9")
let addition = expression <*> %"+" <*> expression
let expression = addition <|> number

expression is left-recursive: its first term is addition, whose first term is expression. This will cause infinite loops every time expression is invoked; try to avoid it.

I love ambiguity more than @numist

Alternations try their left operand before their operand, and are short-circuiting. This means that they disambiguate (arbitrarily) to the left, which can be handy; but this can have unintended consequences. For example, this parser:

%"x" <|> %"xx"

will not parse “xx” completely.

Integration

  1. Add this repository as a submodule and check out its dependencies, and/or add it to your Cartfile if you’re using carthage to manage your dependencies.
  2. Drag Madness.xcodeproj into your project or workspace, and do the same with its dependencies (i.e. the other .xcodeproj files included in Madness.xcworkspace). NB: Madness.xcworkspace is for standalone development of Madness, while Madness.xcodeproj is for targets using Madness as a dependency.
  3. Link your target against Madness.framework and each of the dependency frameworks.
  4. Application targets should ensure that the framework gets copied into their application bundle. (Framework targets should instead require the application linking them to include Madness and its dependencies.)