These are chat archives for Ruhrpottpatriot/GW2.NET

4th
Sep 2016
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 12:14
while we are at it. We need to think about this:
Steven Liekens
@StevenLiekens
Sep 04 2016 12:16
do we have sync methods?
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 12:16
yes, we have. But afaik they are only asnc methods run synchronously
I'd have to check though
Btw: Additionally we are going with the new repository layout I presented further above
Implementing querying by extension methods will save us a massive amount of code
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 12:31
Steven Liekens
@StevenLiekens
Sep 04 2016 12:35
I quickly scanned the first few code examples
he shouldn't have an async method for reading just one character from a buffer...
that method should remain synchronous and instead there should be a separate method FillBufferAsync
his ReadNextAsync method would only make sense if it returned an array of characters
then it wouldn't be called millions of times
and ideally it would be called with a buffer that is as big as the internal buffer
Steven Liekens
@StevenLiekens
Sep 04 2016 12:40
:)
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 12:51
That's what I thought, too. For us it's probably negigible, sice we deal with network IO and always get chunks of data.
Steven Liekens
@StevenLiekens
Sep 04 2016 12:51
it seems crazy to me that you'd buffer 64kb just to get the next character... even worse if you intend to call that method 64000+ times more instead of calling BinaryReader.ReadChars(64 * 1024 - 1)
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 12:52
while we are at it, a simple side project I'm doing deals with async file IO, but I'm not sure if this is the correct implementation:
string path = Path.Combine(this.SaveLocation, "Symbols", symbol.Key, ".symbol");

using (var stream = new FileStream(path, FileMode.Create))
{
    byte[] data = new byte[1024];

   using (BsonWriter writer = new BsonWriter(stream))
   {
      JsonSerializer serializer = new JsonSerializer();
      serializer.Serialize(writer, symbol);
   }

   return stream.WriteAsync(data, 0, data.Length, cancellationToken);
}
Steven Liekens
@StevenLiekens
Sep 04 2016 12:53
that doesn't seem right
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 12:53
thought so
Steven Liekens
@StevenLiekens
Sep 04 2016 12:53
data is never written to
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 12:54
that's the problem. This is the example I'm using
or do I need to create another instance of FileStream and copy the memory stream to it?
Steven Liekens
@StevenLiekens
Sep 04 2016 12:55
the last statement appends 1024 zero's to the end of the file and then returns 1024
though I'm not sure if that even works outside of the using
you might use a MemoryStream if you need more control over how the result is saved to disk
at the cost of more memory usage
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 12:58
like this?
string path = Path.Combine(this.SaveLocation, "Symbols", symbol.Key, ".symbol");

using (var fileStream = new FileStream(path, FileMode.Create))
{
    using (MemoryStream ms = new MemoryStream())
    {
        using (BsonWriter writer = new BsonWriter(fileStream))
        {
                JsonSerializer serializer = new JsonSerializer();
                serializer.Serialize(writer, symbol);
         }
         ms.CopyToAsync(fileStream, 1024, cancellationToken);
     }
        // Write to disk here...
}
Steven Liekens
@StevenLiekens
Sep 04 2016 12:59
yeah
except you don't await the async calls before disposing the stream
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 12:59
ah yes, I should do that
this ok?
using (var fileStream = new FileStream(path, FileMode.Create))
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    using (BsonWriter writer = new BsonWriter(fileStream))
                    {
                        JsonSerializer serializer = new JsonSerializer();
                        serializer.Serialize(writer, symbol);
                    }

                    await ms.CopyToAsync(fileStream, 1024, cancellationToken);

                    await fileStream.FlushAsync(cancellationToken);
                }
      }
Steven Liekens
@StevenLiekens
Sep 04 2016 14:33
yes that should be fine except for one thing
if that's library code then call ConfigureAwait(false) on the task
Steven Liekens
@StevenLiekens
Sep 04 2016 15:18
why is finishing a project always so difficult?
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 15:19
dunno
because you can't find something to do?
Steven Liekens
@StevenLiekens
Sep 04 2016 15:19
development cycle: think of a great idea for a weekend project -> make massive progress in the early stages -> progress slows down -> get bored -> return to step 1
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 15:19
yeah
i know
Steven Liekens
@StevenLiekens
Sep 04 2016 15:45
my text parsing framework is coming along pretty nicely though :)
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 15:45
good to hear
Steven Liekens
@StevenLiekens
Sep 04 2016 15:46
I now have an implementation of System.IO.TextReader that supports seeking and keeps track of the current line and column number
works on strings and streams, even nonseekable streams
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 15:46
nice
I'm really wondering if ParserCombinators are viable in C#
Steven Liekens
@StevenLiekens
Sep 04 2016 15:47
heard of them but can't remember what they are
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 15:48
Basically, you parse input by spliting them into smaller parsers
and then combine them
like this:
boiler :: ReadP Boiler
boiler =
  Hobbyist <$ char 'H'
  <|> Locomotive <$ char 'L'
  <|> Boiler <$ char 'B'
    <*> (HighPressure <$ char 'H' <|> LowPressure <$ char 'L')
    <*> ((,,) <$ char '-'
      <*> (read <$> munch1 isDigit) <* char 'x'
      <*> (read <$> munch1 isDigit) <* char 'x'
      <*> (read <$> munch1 isDigit))
Steven Liekens
@StevenLiekens
Sep 04 2016 15:49
might be what I'm doing
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 15:49
for a string in this format "(H|L|BH-size|BL-size)-temp
makes parsing sooo easy
that's why I like Functional programming so much
Steven Liekens
@StevenLiekens
Sep 04 2016 18:51
well using my framework, each parser rule is a class
so H is a class (HParser), L is a class (LParser) and so on
and there's also an alternation parser
so a simple rule like H|L in my framework is var parser = new AlternationParser(new HParser(), new LParser());
and you can infinitely nest parsers in that way
is that not very similar to parser combinators?
unfortunately, configuration is still much more complicated than I'd like it to be
Steven Liekens
@StevenLiekens
Sep 04 2016 19:33
sample.png
but hey it works
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 19:54
hm, in FP it would go much simpler, since you have some stuff on the low level to help you
take this for example:
Parser a = String -> [(a, String)]
you have a parser of type a, which takes a string and returns an object of type a and the remainder which wasn't parsed
with that you can do this:
item :: Parser Char
item inp = case inp of
             ""   -> []
             x:xs -> [(x,xs)]
you have a parser, which takes a string and returns a char
or if the input is empty, you return an empty set
Steven Liekens
@StevenLiekens
Sep 04 2016 19:57
does that work with ambiguous grammars?
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 19:57
yes
since you now can do the follwing
(|||) :: Parser a -> Parser a -> Parser a
(p ||| q) inp = p inp ++ q inp
this function takes two parsers and returns the concatenation of both
meaning, first runs the left parser and with the input not parsed the second parser runs
it should be possible in C#, too, but you'd have to do much stuiff with Func and Expression
is guess
in F# it's simple
since F# is very similar to Haskell
Steven Liekens
@StevenLiekens
Sep 04 2016 20:09
but what if the left parser eats too many characters or not enough characters
so the right parser can't parse the remainder of the input
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 20:10
in the latter case you get the remaining unparsed string back
Steven Liekens
@StevenLiekens
Sep 04 2016 20:10
ah that's cool :)
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 20:10
see edit
Steven Liekens
@StevenLiekens
Sep 04 2016 20:11
oh not the whole string?
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 20:11
you can code it like this
but usually it's not done
lemme get you an example
for the input string "H-abdex"
I get back [(Hobbyist,"-abdex")]
and then you can check if the right part of the tuple is empty and if not you raise an error
but usually you build your parser, that your first case can't/shouldn't happen
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 21:36
Oh, i just remembered something

but what if the left parser eats too many characters

that's not possible with parser combinators, since you advance through the string char by char and if the result has been reached we return the result and the remainder of the string

Darnell Williams
@Seeker1437
Sep 04 2016 21:41
Wait this is pretty advanced for me but I want to understand... so what is the application for that in this lib?
Steven Liekens
@StevenLiekens
Sep 04 2016 21:41
there's a few areas
one is in item descriptions
the game client has its own sort of markup language for displaying colored item descriptions
I think they call them "flavors"
it's mostly ascended items
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 21:42
yeah
btw
This message was deleted
base framework for a Haskell parser
you can write almost anything with it
in FP we wrote a simple calculator from it
Steven Liekens
@StevenLiekens
Sep 04 2016 21:44
"description" : "<c=@flavor>Crafted in the style of the renowned asuran genius, Zojja.</c>"
parsing that is one place where we need to roll our own parser
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 21:45
wrong gist:
see here for full calculator implementation:
Steven Liekens
@StevenLiekens
Sep 04 2016 21:46
and then the other thing we need to be able to parse is the Link header in bulk responses
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 21:46
Maybe I'll sharpen my F# skills (pun intended)
Since F# and C# interop is easy
Steven Liekens
@StevenLiekens
Sep 04 2016 21:46
oh jeez
Robert Logiewa
@Ruhrpottpatriot
Sep 04 2016 21:47
why write and overly complicated parser, if it can be done way easier
I'd do it in Haskell, but their C# interop goes via C and COM
no thanks.
I think the biggest obstacle in C# for parser combinators is the missing ability to create my own operators
@StevenLiekens for you: https://github.com/sprache/Sprache
and I think we can use that too
would make parsing things like "description" : "<c=@flavor>Crafted in the style of the renowned asuran genius, Zojja.</c>" very easy