Sorry for the long absence. I was intending to post whenever I finished Spinel 0.2.0, but I haven’t been able to get there. One blocker is that my virtual memory system appears to be corrupting everything at spurious moments. I’ve yet to debug what the virtual memory system is doing to cause such a spectacular failure. This may or may not be why my scheduler implementation is broken. At least I have partial implementation of the scheduler.

Spinel 0.2.0 WIP, showing RNG initialization and PCI device searching
There's some new stuff here, but still no usermode!

Perhaps another reason why I still don’t have usermode is that I got seriously sidetracked a couple of times. You can see that I now have a kernelspace RNG. This isn’t just some linear congruential generator, it’s based off of the ChaCha20 stream cipher, also used in {Free,Open,Net,DragonFly }BSD and Linux. It currently doesn’t have a very good scheme for its entropy pool (something was causing memory corruption when using a pool. As discussed above, it turned out to not be the RNG, so I might add a proper pool sometime soon), but it still works! It’s probably not correct since I wrote the implementation and I’m not an expert at cryptography or anything else, but it was still a fun learning experience.

And yet Spinel doesn’t even get to user mode.

If Spinel still sounds interesting to you, check out Spinel on GitHub!

I’m sorry for not getting that much work done. University has continued despite everything, and so have my own mental health issues, although I’m doing a bit better at the moment.

One more thing: recently, I’ve started work on a programming language that I’d like to try to implement as a challenge. Currently, it’s named ColdDivinity. It’s sort of a blend between Rust and C{,++}, with some inspiration from Python, Haskell, and a bit of C# (definitely that and not Java ;)). It doesn’t set out to be a safe language like Rust (although perhaps a safe mode could be devised, and even without it some static analysis would probably be good); it tries to capture what an ideal programming language is for me, so that I can have fun implementing it and then maybe even using it (maybe for a certain operating system?).

Of course, being a language that I’d like to use, it is primarily intended to be compiled to native binaries. Maybe there could be a JIT compiler (the grammar currently makes allowances for a shebang for that reason), but the primary use case is ahead-of-time compilation, like C{,++}, Rust, etc.

I should say up front that I unfortunately don’t have any sort of compiler for this yet, but I’m working on it. I’m struggling a little to write a code generator…

Here’s an example program, written following the prototypical grammar:

import standard.abort;
import standard.io.print;

// "data Foo {...}" creates an algebraic data type
// This is equivalent to Rust's Option
// Of course, the standard library will probably have an optional type
// This is just a demonstration
data MyOption<T> {
    Some(T),
    None
}

// Return type has been elided; the full header is:
// def T getValueOrDie<T>(MyOption<T> val)
def getValueOrDie<T>(MyOption<T> val) {
    switch val {
        case Some(x) {
            x
        }

        case None {
            abort("getValueOrDie didn't get a value, and thus died!");
        }
    }
}

def main() {
    let MyOption<int> naught = MyOption.None;
    let something = MyOption.Some(5);
    print(f"Got {getValueOrDie(something)} from something");
    // will abort
    getValueOrDie(naught);
}

Some notable things:

  • data declares an algebraic data type, like Rust’s enum or Haskell’s data. This keyword is not final; I might change it to something like adt.
  • Return types can be elided.
  • Modules.
  • Python’s f string syntax is planned to be included.
  • Generics! Notable: there will probably be an equivalent to Rust’s impl Trait syntax.
  • Although I used camelCase, no name styles will be enforced by the language.
  • All variables are immutable unless declared mutable, as in Rust.
let int x = 4;
x = 7; // Error

let mutable int y = 4;
y = 7; // Ok
  • Integer overflow is defined behaviour. If you don’t want this, you can use the nooverflow specifier.
let u8 x = 255;
let nooverflow u8 y = 255;
x++; // x = 0
y++; // Error
  • ColD const ≈ C++ const{expr,eval}
const NumItems = 4;
static items = [0; NumItems]; // Bonus: Rust list-filling syntax

def const coolFunction() {
    const if __Endianness == __PDPEndian {
        asm("hcf");
    }
}
  • ColD will have classes, similar to in C++. More below.
  • Rust-like traits, but you can also put member variables in them.

A couple more examples:

Using a lambda

import standard.io.print;

def main() {
    let int[10] numbers = [1..10];
    print(f"The numbers 1-10: {numbers}");
    let numbers = map(lambda (x) { x * x }, numbers);
    print(f"The numbers 1-10, but squared: {numbers}");
}

Classes and traits

import standard.io.print;

trait Lawyer {
    static string name;

    // "nothing" is analagous to void in C or () in Rust/Haskell
    decl public nothing exclaim();

    def public string getName() {
        return name;
    }
}

class Wright implements Lawyer {
    static string name = "Phoenix Wright";

    def public exclaim() {
        print("Objection!");
    }
}

class Edgeworth implements Lawyer {
    static string name = "Miles Edgeworth";

    def public exclaim() {
        print("Eureka!");
    }
}

// A bit tripe but can be expanded upon
// Definitely not final syntax for trait parameters
def makeExclaim(Lawyer l) {
    l.exclaim();
}

def main() {
    let Edgeworth miles;
    let Wright phoenix;
    makeExclaim(phoenix);
    makeExclaim(miles);
}

That went on for quite a bit longer than I thought, especially the part about ColdDivinity. In any case, thank you for reading! See you next time!