-
Notifications
You must be signed in to change notification settings - Fork 62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ignore whitespace, either by default or setting #39
Comments
I don't think this is something that should be built in to the library. You can always factor out repetitive code into a method. Parser<char, T> BetweenWhitespace<T>(Parser<char, T> p) => p.Between(SkipWhitespaces); |
Not sure if this is the correct way to ask for help with a problem … but if not, then please tell me how I can get help … if so, then here we go …
I’ve been enhancing the given simple json parser and trying to enhance it to handle the official json syntax and grammer.
For some odd reason, this statement causes a System.TypeInitializationException:
private static readonly Parser<char, IJson> _JsonArray =
_JsonValue
.Separated(_Comma)
.Between(_LBracket, _RBracket)
.Select<IJson>(els => new JsonArray(els.ToImmutableArray<IJson>()));
And when I comment it out, everything runs correctly.
Here is my source:
Json object classes:
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
namespace gof.KnowledgeBase.Parsers.Json
{
public interface IJson
{
#region functional methods
// json set of objects to formatted string
string ToFormattedString(int depth);
// descriptive strings for debugging
string ToDescriptiveString();
#endregion functional methods
}
public class JsonObject : IJson
{
#region properties
public ImmutableArray<KeyValuePair<string, IJson>> Members { get; }
#endregion properties
#region ctors
public JsonObject(ImmutableArray<KeyValuePair<string, IJson>> members)
{
Members = members;
}
#endregion ctors
#region overrides
public override string ToString()
=> $"{{{string.Join(",", Members.Select(kvp => $"\"{kvp.Key}\":{kvp.Value.ToString()}"))}}}";
public virtual string ToFormattedString(int depth)
=> $"{new string(' ', depth)}{{{string.Join(string.Concat(",", System.Environment.NewLine, new string(' ', depth+1)), Members.Select(kvp => $"\"{kvp.Key}\":{kvp.Value.ToFormattedString(kvp.Key.Length + 4)}"))}}}";
public virtual string ToDescriptiveString()
=> $"{{{string.Join(",", Members.Select(kvp => $"\"{kvp.Key}\":{kvp.Value.ToDescriptiveString()}"))}}}";
#endregion overrides
}
public class JsonArray : IJson
{
#region properties
public ImmutableArray<IJson> Elements { get; }
#endregion properties
#region ctors
public JsonArray(ImmutableArray<IJson> elements)
{
Elements = elements;
}
#endregion ctors
#region overrides
public override string ToString()
=> $"[{string.Join(",", Elements.Select(e => e.ToString()))}]";
public virtual string ToFormattedString(int depth)
=> $"[{string.Join(string.Concat(",", System.Environment.NewLine, new string(' ', depth + 1)), Elements.Select(e => e.ToFormattedString(depth)))}]";
public virtual string ToDescriptiveString()
=> $"[{string.Join(",", Elements.Select(e => e.ToDescriptiveString()))}]";
#endregion overrides
}
public class JsonString : IJson
{
#region properties
public string Value { get; }
#endregion properties
#region ctors
public JsonString(string value)
{
Value = value;
}
#endregion ctors
#region overrides
public override string ToString()
=> $"\"{Value}\"";
public virtual string ToFormattedString(int depth)
=> $"\"{Value}\"";
public virtual string ToDescriptiveString()
=> $"String \"{Value}\"";
#endregion overrides
}
public class JsonNumber : IJson
{
#region properties
public string Value { get; }
#endregion properties
#region ctors
public JsonNumber(string value)
{
Value = value;
}
#endregion ctors
#region overrides
public override string ToString()
=> $"{Value}";
public virtual string ToFormattedString(int depth)
=> $"{Value}";
public virtual string ToDescriptiveString()
=> $"Number {Value}";
#endregion overrides
}
public class JsonConstant : IJson
{
#region properties
public string Value { get; }
#endregion properties
#region ctors
public JsonConstant(string value)
{
Value = value;
}
#endregion ctors
#region overrides
public override string ToString()
=> $"{Value}";
public virtual string ToFormattedString(int depth)
=> $"{Value}";
public virtual string ToDescriptiveString()
=> $"Constant {Value}";
public virtual object ToObjectValue()
=> (Value.Equals("true", StringComparison.CurrentCultureIgnoreCase) ? (object) true : (Value.Equals("false", StringComparison.CurrentCultureIgnoreCase) ? (object) false : (object) null));
#endregion overrides
}
}
Here is the Json Parser:
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using Pidgin;
using static Pidgin.Parser;
using static Pidgin.Parser<char>;
namespace gof.KnowledgeBase.Parsers.Json
{
public static class JsonParser
{
#region constants
private static readonly Parser<char, char> _LBrace = Char('{').Between(SkipWhitespaces);
private static readonly Parser<char, char> _RBrace = Char('}').Between(SkipWhitespaces);
private static readonly Parser<char, char> _LBracket = Char('[').Between(SkipWhitespaces);
private static readonly Parser<char, char> _RBracket = Char(']').Between(SkipWhitespaces);
private static readonly Parser<char, char> _Colon = Char(':').Between(SkipWhitespaces);
private static readonly Parser<char, char> _Comma = Char(',').Between(SkipWhitespaces);
private static readonly Parser<char, char> _Escape = Char('\\');
private static readonly Parser<char, char> _Quote = Char('"');
private static readonly Parser<char, char> _Underscore = Char('_');
private static readonly Parser<char, string> _EscapeQuote = Map((e, q) => string.Concat(q), _Escape, _Quote);
private static readonly Parser<char, string> _QuoteQuote = Map((q1, q2) => string.Concat(q2), _Quote, _Quote);
private static readonly Parser<char, string> _ConstantTrue = String("true");
private static readonly Parser<char, string> _ConstantFalse = String("false");
private static readonly Parser<char, string> _ConstantNull = String("null");
#endregion constants
#region grammar syntax rules
private static readonly Parser<char, string> _IdentifierFirstChar = Letter.Or(_Underscore).Select<string>(c => string.Concat(c));
private static readonly Parser<char, string> _IdentifierRemaining = LetterOrDigit.Or(_Underscore).ManyString();
private static readonly Parser<char, string> _Identifier = Map((f, r) => string.Concat(f, r), _IdentifierFirstChar, _IdentifierRemaining);
private static readonly Parser<char, string> _QuotedIdentifier = _Identifier.Between(_Quote);
private static readonly Parser<char, IJson> _JsonIdentifier = _QuotedIdentifier.Between(SkipWhitespaces).Select<IJson>(s => new JsonString(s));
private static readonly Parser<char, string> _LiteralChar = AnyCharExcept('"').Select<string>(c => string.Concat(c));
private static readonly Parser<char, string> _LiteralString = Try(Try(Try(_EscapeQuote).Or(_QuoteQuote)).Or(_LiteralChar)).ManyString().Between(_Quote);
private static readonly Parser<char, IJson> _JsonString = _LiteralString.Between(SkipWhitespaces).Select<IJson>(s => new JsonString(s));
private static readonly Parser<char, IJson> _JsonNumber = LongNum.Between(SkipWhitespaces).Select<IJson>(n => new JsonNumber(n.ToString()));
private static readonly Parser<char, IJson> _JsonArray =
_JsonValue
.Separated(_Comma)
.Between(_LBracket, _RBracket)
.Select<IJson>(els => new JsonArray(els.ToImmutableArray<IJson>()));
//private static readonly Parser<char, IJson> _JsonValue = Try(Try(Try(Try(_JsonString).Or(_JsonNumber)).Or(_JsonObject)).Or(_JsonArray));
//private static readonly Parser<char, IJson> _JsonValue = Try(Try(Try(_JsonString).Or(_JsonNumber)).Or(_JsonObject));
//private static readonly Parser<char, IJson> _JsonValue = Try(Try(_JsonString).Or(_JsonNumber));
//private static readonly Parser<char, IJson> _JsonValue = _JsonString.Or(Rec(() => _JsonNumber)).Or(Rec(() => _JsonObject)).Or(Rec(() => _JsonArray));
private static readonly Parser<char, IJson> _JsonValue = _JsonString.Or(Rec(() => _JsonNumber)).Or(Rec(() => _JsonObject));
private static readonly Parser<char, KeyValuePair<string, IJson>> _JsonKvp =
_QuotedIdentifier
.Before(_Colon)
.Then(_JsonValue, (key, val) => new KeyValuePair<string, IJson>(key, val));
private static readonly Parser<char, IJson> _JsonObject =
_JsonKvp
.Separated(_Comma)
.Between(_LBrace, _RBrace)
.Select<IJson>(kvps => new JsonObject(kvps.ToImmutableArray<KeyValuePair<string, IJson>>()));
#endregion rules
#region callable parser
public static Result<char, IJson> ParseIdentifier(string input) => _JsonIdentifier.Parse(input);
public static Result<char, IJson> ParseString(string input) => _JsonString.Parse(input);
public static Result<char, IJson> ParseNumber(string input) => _JsonNumber.Parse(input);
public static Result<char, IJson> ParseValue(string input) => _JsonValue.Parse(input);
public static Result<char, IJson> Parse(string input) => _JsonObject.Parse(input);
//public static Result<char, IJson> Parse(TextReader input) => JsonObject.Parse(input);
#endregion callable parser
}
}
Here is the code I’m using to do unit testing:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Pidgin;
using static Pidgin.Parser;
using gof.KnowledgeBase.Parsers.Json;
namespace ParsingPidginTester
{
class Program
{
static void Main(string[] args)
{
// local vars
string jsonSource;
Result<char, IJson> jsonParseResult;
// parse a simple json structure
jsonSource = "{ \"GameDrawEntity\" : { \"Id\" : \"2019-07-10\" , \"Set1Ball1\" : \"1\" }}";
Console.WriteLine($"{jsonSource}");
jsonParseResult = JsonParser.Parse(jsonSource);
Console.WriteLine(jsonParseResult.Value.ToString());
// parse a simple json structure
jsonSource = "{ \"myEntity\" : { \"Id\" : \"12345\" , \"Balls\" : [\"1\", \"2\", \"3\", \"4\",\"5\"] }}";
Console.WriteLine($"{jsonSource}");
jsonParseResult = JsonParser.Parse(jsonSource);
Console.WriteLine(jsonParseResult.Value.ToString());
Console.Read();
}
}
}
Any help would be greatly appreciated.
Michael Lee
Sent from Mail<https://go.microsoft.com/fwlink/?LinkId=550986> for Windows 10
…________________________________
From: Scott McDonald <notifications@github.com>
Sent: Wednesday, May 22, 2019 12:59:44 PM
To: benjamin-hodgson/Pidgin
Cc: Subscribed
Subject: [benjamin-hodgson/Pidgin] Ignore whitespace, either by default or setting (#39)
I have been finding it arduous to constantly add SkipWhitespaces with Before or Between methods for various parsers. Does it make sense to have char based parsing automatically ignore whitespace or by setting to simplify parser creation?
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub<#39?email_source=notifications&email_token=AMAC3ULB66U3EOSCT7UPFNTPWV3YBA5CNFSM4HOWHM52YY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4GVINJ6Q>, or mute the thread<https://github.com/notifications/unsubscribe-auth/AMAC3UKY27YYZLIPEDCQYA3PWV3YBANCNFSM4HOWHM5Q>.
|
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I have been finding it arduous to constantly add
SkipWhitespaces
withBefore
orBetween
methods for various parsers. Does it make sense to havechar
based parsing automatically ignore whitespace or by setting to simplify parser creation?The text was updated successfully, but these errors were encountered: