2 ms·
Wanted to leave a comment on the site, but it seems comments are broken, so I'll stick this here just in case the author sees it: You've linked to my csharp-mo
by louthy 9y ago
Wanted to leave a comment on the site, but it seems comments are broken, so I'll stick this here just in case the author sees it:
You've linked to my csharp-monad library for C# parser combinators. This has been superseded by my language-ext project: https://github.com/louthy/language-ext/ https://github.com/louthy/language-ext/
It is a much more advanced and efficient port of the Haskell Parsec library. Would you mind linking to that instead?
Your Sprache examples would look like this in language-ext:
public static readonly Parser<JCLCommand> JCLText =
from open in ch('$')
from ws1 in spaces
from command in asString(many(noneOf(' ')))
from ws2 in spaces
from content in asString(many(noneOf('"')))
select new JCLCommand(command, content);
public static readonly Parser<JCLCommand> GlobalText =
from variablename in asString(many(noneOf('=')))
from ws2 in ch('=')
from openbrack in ch('(')
from filepath in asString(many(noneOf(')')))
from closebrack in ch(')')
select new JCLCommand(variablename, filepath);
But the power of parser combinators are their reusable nature. So I'd break that down to a set of tools:
static Parser<A> token<A>(Parser<A> p) =>
from x in p
from _ in either(spaces, eof)
select x;
static Parser<string> symbol(string x) =>
token(str(x));
static Parser<string> identifier =
token(asString(many1(alphaNum)));
static Parser<A> quotes<A>(Parser<A> p) =>
between(symbol("\""), symbol("\""), p);
static Parser<A> parens<A>(Parser<A> p) =>
between(symbol("("), symbol(")"), p);
static Parser<string> quoteText =
token(quotes(asString(many(satisfy(x => x != '"')))));
static Parser<string> parensText =
token(parens(asString(many(satisfy(x => x != ')')))));
Then your final parsers would look like this:
static readonly Parser<JCLCommand> JCLText =
from open in symbol("$")
from command in identifier
from content in quoteText
select new JCLCommand(command, content);
static readonly Parser<JCLCommand> GlobalText =
from variablename in identifier
from ws2 in symbol("=")
from filepath in parensText
select new JCLCommand(variablename, filepath);
static readonly Parser<Seq<JCLCommand>> Commands =
from _ in spaces
from commands in many1(either(JCLText, GlobalText))
select commands;
Which is much easier to understand I think. It's not exactly the same as it defines what an identifier is, but it's much more tolerant of rogue spaces because of the token parser. This is definitely the most compelling aspect of parser combinators for me, the way they compose so elegantly.