Skip to content

Instantly share code, notes, and snippets.

@aaronpowell
Last active February 26, 2019 01:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aaronpowell/ae1d96f3c185dc2a015229526f711bc3 to your computer and use it in GitHub Desktop.
Save aaronpowell/ae1d96f3c185dc2a015229526f711bc3 to your computer and use it in GitHub Desktop.
C# parser in F#
using System;
using System.Collections.Generic;
namespace Parser.CSharp
{
public static class ParserCSharp
{
public static string[] ParseCommandline(string input)
{
var items = new List<string>();
var buffer = string.Empty;
var hold = false;
foreach (var s in input)
{
if (s == '"')
{
if (hold)
{
items.Add(buffer);
buffer = string.Empty;
hold = false;
}
else
{
hold = true;
}
continue;
}
if (s == ' ' && !hold)
{
if (buffer != string.Empty)
{
items.Add(buffer);
}
buffer = string.Empty;
continue;
}
buffer += s;
}
if (buffer != string.Empty)
items.Add(buffer);
return items.ToArray();
}
}
}
namespace Parser.FSharp
module ParserFSharp =
type ParseState = { holding: bool; buffer: string; items: string list }
let addBufferToItems state =
{state with buffer=""; items=state.buffer :: state.items}
let parseChar state =
function
| '"' when state.holding ->
{state with holding=false} |> addBufferToItems
| '"' ->
{state with holding=true}
| ' ' when not state.holding ->
if state.buffer = "" then state
else addBufferToItems state
| c ->
{state with buffer=state.buffer + (string c)}
let parseCommandline line =
let finalState = match (Seq.fold parseChar {holding=false; buffer=""; items = []} line) with
| fs when fs.buffer = "" -> fs
| fs -> addBufferToItems fs
List.rev finalState.items
using System;
using System.Collections.Generic;
using Parser.CSharp;
using Parser.FSharp;
using Xunit;
namespace Parser.Tests
{
class DataSource {
private static List<object[]> data = new List<object[]> {
new object[] { "help", new[] { "help" } },
new object[] { "help user", new[] { "help", "user" } },
new object[] { "user change-password admin P@55-w0rd!1", new[] { "user", "change-password", "admin", "P@55-w0rd!1" } },
new object[] { "user change-name admin \"Aaron Powell\"", new[] { "user", "change-name", "admin", "Aaron Powell" } }
};
public static IEnumerable<object[]> TestData
{
get { return data; }
}
}
public class ParserTests
{
[Theory]
[MemberData(nameof(DataSource.TestData), MemberType = typeof(DataSource))]
public void RunTests_CSharp(string key, string[] value)
{
var result = ParserCSharp.ParseCommandline(key);
Assert.Equal(value, result);
}
[Theory]
[MemberData(nameof(DataSource.TestData), MemberType = typeof(DataSource))]
public void RunTests_FSharp(string key, string[] value)
{
var result = ParserFSharp.parseCommandline(key);
Assert.Equal(value, result);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment