Activity

Andraaal

Shipped this project!

Hours: 16.39
Cookies: 🍪 323
Multiplier: 16.4 cookies/hr

In short I built a programming language, but I couldn’t finish it until the end of flavortown, so it is now some weird mixture between language and calculator. A calculator with super-powers if you will.

The thing I’m proud of the most, is that is has got proper error reporting. Like when I make a syntax error it can tell me where it happened and what is wrong. Isn’t that cool?

I won’t bother reciting what things it can do, if you want to know go read the README

Andraaal

First off a correction: In my previous devlog I wrote “Writing the parser”, when I was obviously writing the
interpreter. Sorry for that. (Maybe I should stop writing these after midnight… - Me writing this at 1:30 AM)

Probably the last devlog for sylex

Since flavortown is going to end tomorrow this is likely the last devlog I will make for sylex. I did mainly two things:

  • Allow execution from CLI
  • Add some builtins
  • I also changed a lot of small things to give the project some polish

CLI execution

This was a rather straightforward feature to implement. I added two modes of execution: Files and REPL. In file mode you
just specify a file and it will execute it. REPL mode though is like a mini interactive enhanced calculator-like thingy.
Semicolon rules are relaxed and everything gets printed by default.

Builtins

I only did a few builtins, but it feels so good having finally something a bit more advanced than just basic arithmetic.
There is now sin, cos and tan, a print function: print. And then I realized that a REPL without an exit
function will cause anyone to give me a 1 in usability, so I added that too.

Random other enhancements too

I added the ternary operator to have some useful things in my language and so that strings are not completely useless.
Then I copied my GitHub Actions workflows from my other projects (still took my 3 tries to get everything right). I also
expanded the README, so people know what I even did. Also probably twenty more little tweaky I don’t remember anymore.
And 0 isn’t truthy anymore.

Well that’s it for now. I am going the create an actually useful pic and then this bad boy gets shipped!

Attachment
Attachment
0
Andraaal

Next Devlog

There is your next devlog; have fun reading it

Adding more expressions

I added logical and/or operators and all eight of the comparison operators. For those of you wonder what the heck the other two operators are, they are the three-way comparisons: <=> and >=<. They evaluate to -1, 0 and 1 depending on if their values are greater/smaller/equal. Adding them was really easy, because all the architecture needed to support them was already there. I’m talking about 1 minute or 2; I spent more time writing this paragraph than implementing
them.

Printing lexer errors

This was a really stupid mistake, I noticed that comment tokens are not filtered out and crash the parser, so I quickly fixed that.

Writing the parser

First I create a Value type, which can currently be either a number (float or int), a string or a bool. Then I wanted to recursively match the expression, but I ran into a problem: If you have two types of number, and you want to do arithmetic with an arbitrary combination of them you are gonna need a lot of matches. Luckily this can be reduced a bit by using function pointers, but I still had to write everything twice: Once for floats and once for ints.

Then came the three-way-comparators and I discovered that they are actually four-way-comparators, because there is this case where there is no ordering. Like when on of the operands is NAN. That means three-way-comparison is off the table for now, since there is no sane way to represent the results with my rather limited datatypes. Anyways the rest of the Parser should work now (I hope - I haven’t tested it yet).

Dear flavortown team

what’s up with your markdown? I just noticed that single linebreaks are rendered in my devlogs. Why? That’s not supposed to be the case in markdown for a reason. Editing your paragraphs in a single long line is just obnoxious.

Attachment
0
Andraaal

Since I got feedback, that I don’t write enough devlogs I will try to improve that and do one every 5h. (Not sure if I can keep that up, but we’ll see…).

What did I do

This was not my first time writing a parser, specifically a Pratt-Parser, so kind of knew what I was doing, but at the same time wanted to do a bit too much. I decided, since I already had experience, that I wanted to do some nice error handling this time, so that the error messages can at least point you into the right direction.

Testing

Then I started to write some tests for the parser, but quickly stopped again, because I realized that it would be a huge pain creating all these nested data-structures by hand, so I threw my concept of a library overboard and turned it into an executable. Not the “correct” choice, I know, and yes, I could have done it with AI, but I didn’t feel like doing either of that, so I just skipped it. Maybe I will generate some test-cases later on.

What did I learn

Even though I already did one of these things, creating one with proper error handling was quite the experience. First I just wanted to create my own error type, but then Copilot told me to use a library instead, so I spent about an hour figuring out how that worked and which library to use (There are some massive differences between thiserror and anyhow).

static vs const

After that was done I wanted to create a truly const parsing table this time after just using a function with hard-coded values last time. I again tried to ask AI and it told me to use static for that. Of course, shortly after I discovered that static is not the way to go and const is actually preferable here. Who would have thought that you use const for constants…

refactoring error-handling

I again tried using AI for refactoring the creation of errors (I know, I should have learned my lesson by now), as constructing one takes 5 lines and is quite verbose. Of course I first tried myself, but all of my solutions were rejected by the borrow-checker, so eventually I gave up. The AI however managed to create something that worked: A static function that takes every single field of my Error struct as arguments, puts them together and returns the product. Using that would save exactly 0 lines of code and make it even more confusing. Well done Copilot!

Attachment
Attachment
0
Andraaal

For having spent so much time here I have done surprisingly little. A lot of it was spent setting the project up, fighting with Cargo, rust’s package manager (Still my favourite package manager by far) and going back and forth on if this should be an executable or a library. Decisions have been made, but are subject to change. The rest of the time was spent actually coding. I am happy to report, here is my new Scanner/Tokenizer:

Features

  • A ton of different tokens (why did I make so many?), no tokens for keywords yet
  • Turning a String into tokens
  • Somewhat reasonable error messages with line numbers/columns
  • I just noticed: No String literals yet either
  • A bunch of tests to verify behaviour (actually found a bug while writing them)

Keeping it short this time, because there wasn’t really anything noteworthy, just parsing strings as usual. Screenshots are also just some random objects and tests

Attachment
Attachment
0
Andraaal

Shipped this project!

Hours: 34.73
Cookies: 🍪 609
Multiplier: 17.54 cookies/hr

mash

I built a simple shell. You know the thing were you type commands and then magically something happens on your computer?
This is it. Here’s what I built in a little more detail:

Features

  • Executable execution: This is obviously a requirement for any shell and one of the core features of mash.
  • Basic Builtins: mash supports some of the most important (or simple) builtins. Here is a quick list
  • IO Interconnection (pipes, etc…): This was by far the most difficult feature to implement. Now though you can
    pipe stdin, out and err freely between any combination of builtin and external command.
  • Command Chronic: History is saved, can be viewed and executed. Also includes history persistence for good
    measure.
  • Advanced Aliasing: Not really that advanced, but you know… that was the best thing I could come up with for A.
    Anyways, mash supports creating and removing aliases for commands and aliases are resolved recursively to support
    using aliases within aliases, if you need that for whatever reason. Plus persistence between sessions to make them
    actually useful.

Storytime

I originally started this project about half a year ago at codecrafters.io. I finished the
core tasks no problem, but when I got to IO redirection my architecture started to fall apart (There wasn’t any notion
of expressions, it was just pure string manipulation). Then, when flavortown started, I finally convinced myself to
write a proper parser. In the end the parser wasn’t really much of a problem, as I had written one before. Finding a
data-structure that somehow combined Commands and Builtins proved to be much more difficult, because I didn’t do my
research.

First I followed some examples on how to redirect IO, but they only showed the convenient way if you have a
fixed pattern, which didn’t work if you wanted to create arbitrary connections between commands. Only after wasting a
bunch of time trying a lot of different strategies I realized you could also just create a new OS-pipe manually and use
that.

I just realized how long this has become and that I should stop ranting, but there is one more thing I wanted to talk
about: mash probably has more dead code than any of my other projects. I created a lot of infrastructure for future
expansions, which I ended up never creating. So in the unlikely case that anyone would like to add something like stdin
from a file that is really easy to do. You’re welcome.

End

Creating a shell was a neat experience and actually not that difficult once I got my overall design figured
out. But I suppose you could say that about anything: Once you figured it out, it became easy.

If anyone actually took the time to read all of this: Thank you! That means a lot to me. I hope you learned something
new or at least found it interesting to read. Cheers!

Andraaal

I did not expect to write another devlog for this project, because the code was finished. But, here we go again:

New Features

None

Bug Fixes

Also None

So what did I do?

I spent way too creating some GitHub Actions to automatically generate and publish the docs and to compile the binaries for people who don’t want to compile them themselves. It took hours and about 50 (FIFTY!!) commits (now squashed) of messing around with my workflow files to get something working. And the worst part is that you can’t test anything locally, you always have to push everything to GitHub and then wait until their server is done compiling everything, only to notice that the binaries overwrite each other or that you forgot to link glibc or something stupid.

Where did the absurd amount of hours come from?

I noticed that hackatime also tracked all the time I previously spent on this project and since I have never submitted it to Hackclub I thought why not include it here.

Attachment
0
Andraaal

I think this is it. My first complete project on flavortown! Yay!!
But before I go celebrate, here is what I did:

New Features

  • Aliases: Really the only new feature for mash in this devlog, as I focused mostly on fixing bugs and crashes and writing documentation. Anyways, you can now create and remove aliases with alias and unalias. I know you missed that `ll, at least I did.

Bug Fixes

I fixed a load of bugs, here are a few I can remember off the top of my head:

  • Fixed a crash when the user requested more history than was available.
  • Fixed a crash when mash syntax was at the end of the input
  • Some more I can’t remember right now…

Misc

  • I disabled all the dead code warnings from clippy, because I have way more infrastructure, than is actually used in any of my commands. Redirecting the stdin of a builtin is just nothing you do every day.
  • Many refactorings, expanding docs and writing a README with the help of AI

This is it - now I just have to figure out how I can create a web-demo to ship this project. Rust to WASM is great, but a shell in the web not so much…

Attachment
0
Andraaal

So… Devlog time!

New Features

  • History: At first I wanted to do this by hand, because I mean what else would you do? When I googled how to do that though the only things I found were a bunch of people on Reddit warning everyone. Apparently doing anything more than just reading is incredibly complicated, so I decided to follow their suggestions and use this library called rustyline. As it turns out using this library was kind of miserable too. The documentation is just rather .. sparse. To not say a bunch of one-liners and a half-hearted example. Still better than doing it by hand though, I guess. One major upside of using this library though, was that it has a lot of other features too, like …
  • Autocomplete: Yes, that’s only here because it came along with the library pretty much for free. Now mash supports completing Builtins, executables in PATH and files/directories.
  • Editing in the terminal: While I had to at least set up the autocomplete, the editing capabilities of rustyline are just there out of the box. After implementing the history I was very pleasantly surprised when I discovered this during testing.

Bug Fix

  • Builtin arguments could be overwritten they were written multiple times. Didn’t really matter, but still.

TODOs

  • Actually use stdin on some builtin after setting it all up
  • Fix the bug where it crashes at startup While taking the screenshots I realized scanning for executables in PATH is the problem. Probably just takes too long checking if some hundred files are executable and doing a syscall for each. I took it out for now.
  • Refactor some parts of the code
  • Maybe: Add aliases
    When looking at this list right know, I realized there is actually not much left. Maybe I can ship this soon?
Attachment
0
Andraaal

I finally managed to setup hackatime. It took me way too long to realise that I have to install the plugin AND run the setup script. In the process of figuring that out I then somehow broke my config file again. In short: It was a huge mess. Anyways, it’s up and running now.

Besides fighting with hackatime (mostly the wakatime plugin actually) I also made some changes to mash:

  • Pipes between external commands and builtins are now working correctly
  • Redirecting stdout/stderr to files is now possible too

The next thing I want to implement is history. Rewriting every command every time for testing is just getting way too tedious. This is probably also a good point to mention that this is my first devlog and first time in a hackclub event. I am super excited!

Attachment
0