This correctly identifies and parses escape characters such as \n, \t, etc.
However, the StringNode in the AST contains the exact string of characters as present in the source. I think this is actually incorrect - the AST should contain the parsed representation of the string. This is why I'm using a parser :)
The question is: what's the best way to obtain the unescaped string?
One option would be to do the unescaping after parsing, ie. "~> (s => StringNode(unescape(s)))". Yet this seems like a rather strange thing to do, given it means parsing the same string again, and also I don't know of an "unescape" function I could use (any suggestions?).