1. 8

As suggested here:

https://lobste.rs/s/8bdt2x/what_are_you_doing_this_weekend#c_do3oyw

  1.  

  2. 5

    Personally I started porting my programming language implementation to Rust. I originally wrote it in Python because the syntax was nearly Python compatible, now that Python has type annotations. I thought I’d be able to more easily self-host if I wrote it in Python. The syntax has diverged enough now (no more ‘class’ keyword, for one thing) that I can’t parse the Python code with my parser anymore, so the value of writing it in Python is lower. I love Python but it isn’t good for handling things that should really be ADTs like syntax trees. I ended up having to write some pretty gnarly code for overloading methods which ends up reading quite nicely but is really just fighting the language, e.g. https://git.sr.ht/~milesrout/beetle/tree/master/typechecker.py#L455-1069

    I’ve been a pretty outspoken critic of Rust in the past but it’s been a long time since I’ve used it so I thought I’d give it a go again. I’ve been pretty pleasantly surprised at how much of the Python code translates over almost line-for-line. The recursive descent parser is essentially line-for-line. I love ‘explicit self’ in both Rust and Python, I must say. They feel like very similar languages in some ways, weirdly.

    The biggest pain point was converting the scanner. In the Python version the scanner is a generator that produces tokens. There’s a ‘lex’ generator that generates raw tokens using a regular expression, then a bunch of iterator adaptors that handle the indentation-sensitive syntax: converting the raw input tokens into lines with an indent amount, then converting those into newline, indent and dedent tokens, then splitting the dedent tokens for cases like:

    if foo:
        if bar:
            baz()
    # for the grammar to work, you need two dedent tokens here, not one
    quux()
    

    The conversion is all quite stateful, and converting the Python generators to explicit state machines was a horrible experience. A simple while <cond>: yield <token> ends up requiring a whole lot of state management and just.. yuck. I can’t wait for Rust to get first class generators so I can just write code like this which might be ugly, complex code at first glance but is very straightforward when you step through it.

    The parts of Rust I don’t really like haven’t changed much. The line noise is really bad, Cargo is very easy but the ease of adding dependencies means it already takes forever to compile even my really simple program from scratch. The module system is arcane and absolutely horrible compared to e.g. Python’s. I just want to import my other files, how hard can it be? Instead I have to write mod scanner; and mod parser; in my main file, or something? I don’t understand it at all.

    Good points: very readable code, I have confidence it’s safe, I haven’t run into borrow checking issues for the most part, and I’ve found it a lot easier to write than last time I tried. One borrow-checking issue I had was trying to move out of a field in a &mut self function so I could drain a vector and replace it with a new vector. I ended up creating a temporary, using mem::swap to swap the field with the temporary vector, then drain the local variable (which was obviously pointing to what the field used to point to), then replaced the field with a new vector. It was a pain, but wasn’t really too bad in the end given the benefits of the borrow checker.

    The other borrow checking issue I had was that I wanted each stage of my scanning and parsing pipeline to have a mutable reference to a ‘context’ so they can record errors, but obviously they can’t all have it at once. None of them use it simultaneously, though. I ended up just using an Rc<RefCell<Context>> because none of them call into the previous ‘layer’ while using the context, which is the only way they could both need a mutable reference to it at the same time. I think this is the idiomatic way of doing it? I’m really not sure.

    1. 3

      Took down the Xmas decorations, as planned. Used our fireplace to dispose of the tree - something discouraged by environmentalists but I found it fun and kinda soothing.

      We have also watched a bunch of old TV.

      1. 3

        Almost finished with the legs for my woodworking bench. It seems the workbench won’t take as long as I thought. Also almost made a tent for my split keyboard (will finish it up tomorrow). Otherwise spent time with family and friends.

        1. 2

          I’ve worked on generator of meaningness.com to epub: https://github.com/Bystroushaak/meaningness.com_epub_generator

          I’ve also did a bit of 3D modeling in blender on the illustration I want to use in blog.

          1. 2

            Began developing an archive viewer for Zulip in Haskell.

            1. 2

              I tried enabling Markdown highlighting for an editor I use [1], but I realized that its using an incomplete and old version of Scintilla, so I would essentially need to write a new lexer. Another editor [2] I have used already has Markdown highlighting, and recently fixed some highlighting problems with YAML, so I started using it.

              1. https://github.com/zufuliu/notepad2
              2. https://github.com/rizonesoft/Notepad3