Last active
January 19, 2017 06:50
-
-
Save sdether/2c7bd811516929dc519698b3dc6fcf55 to your computer and use it in GitHub Desktop.
Expressing ABNF syntax as types and building grammar from those types
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
trait Rule {} | |
object ALPHA extends Rule | |
object DIGIT extends Rule | |
object OCTET extends Rule | |
case class Alternative(rules: Rule*) extends Rule | |
case class Concatenation(rules: Rule*) extends Rule | |
case class SpecificRepetition(rule: Rule, n: Int) extends Rule | |
case class VariableRepetition(rule: Rule, lower: Option[Int] = None, upper: Option[Int] = None) extends Rule | |
case class Terminal(value: String) extends Rule | |
case class Range(lower: Char, upper: Char) extends Rule | |
case class Single(c: Char) extends Rule | |
object CookieDateParser { | |
val timefield = VariableRepetition(DIGIT, Some(1), Some(2)) | |
val hmsTime = Concatenation(timefield, Terminal(":"), timefield, Terminal(":"), timefield) | |
val nonDigit = Alternative(Range(0x00, 0x2f), Range(0x3a, 0xff)) | |
val time = Concatenation(hmsTime, Concatenation(nonDigit, VariableRepetition(OCTET))) | |
val year = Concatenation( | |
VariableRepetition(DIGIT, Some(2), Some(4)), | |
Concatenation(nonDigit, VariableRepetition(OCTET)) | |
) | |
val month = Concatenation( | |
Alternative( | |
Terminal("jan"), Terminal("feb"), Terminal("mar"), Terminal("apr"), Terminal("may"), Terminal("jun"), | |
Terminal("jul"), Terminal("aug"), Terminal("sep"), Terminal("oct"), Terminal("nov"), Terminal("dev") | |
), | |
VariableRepetition(OCTET) | |
) | |
val dayOfMonth = Concatenation( | |
VariableRepetition(DIGIT, Some(1), Some(2)), | |
Concatenation(nonDigit, VariableRepetition(OCTET)) | |
) | |
val nonDelimiter = Alternative( | |
Range(0x00, 0x08), | |
Range(0x0a, 0x1f), | |
DIGIT, | |
Terminal(":"), | |
ALPHA, | |
Range(0x7f, 0xff) | |
) | |
val delimiter = Alternative( | |
Single(0x09), | |
Range(0x20, 0x2f), | |
Range(0x3b, 0x40), | |
Range(0x5b, 0x60), | |
Range(0x7b, 0x7e) | |
) | |
val dateToken = VariableRepetition(nonDelimiter, Some(1)) | |
val dateTokenList = Concatenation( | |
dateToken, | |
VariableRepetition(Concatenation(VariableRepetition(delimiter, Some(1)), dateToken)) | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I can see how to write a parser that pattern matches over some
Rule
composition, but I cannot figure out how to weave the extracting into that parser. Clearly each definition above needs to instead be some monadic wrapper capturing both the rule composition and the resulting type, but I'm struggling making the leap to that abstraction