This page lists various projects I have worked on, organised by most recent to least recent. Project information and links to source code are included whenever possible.

A work in progress functional programming language that compiles to LLVM IR.

My homepage and portfolio site. Currently I host social media links, project information and a blog. The site uses plain HTML and CSS with very little JavaScript; a custom site generator was written using Ruby to maintain consistency between pages. This also helped reduce the burden of creating content by parsing information from other file formats, such as YAML or Markdown. A mature web development framework, such as Rails, Django or React, was not used since it would be inappropriate for a simple static site.

The website also offers the ability to change the theme by clicking the lightbulb symbol on the sidebar, with Figures 1 and 2 showing this effect.

Dark theme
Figure 1. Dark theme
Light theme
Figure 2. Light theme

A simple linter for GameMaker Language that lets teams ban access to certain global variables, or detect semantic problems with your games that GameMaker does not. GMLint attempts to offer clear and concise error messages (as shown in Listing 1), inspired by state-of-the-art solutions like the Rust and Elm compilers.

error (banned-functions) in testfiles/scripts/idiomatic-gml.gml:34:17
 34 |  for (var i=0;i<array_length(keys);i++) {
    |                 ^^^^^^^^^^^^ accessing this variable is prohibited
    = note: `//# WARN banned-functions` is enabled by default

error (bad-tab-style) in testfiles/scripts/idiomatic-gml.gml:72:30
 72 |   if (gamepad_is_connected(i) ) {
    |                              ^ tab is used here when it shouldn't be
    = note: `//# WARN bad-tab-style` is enabled by default

displayed 2 errors for testfiles/scripts/idiomatic-gml.gml

error (banned-functions) in testfiles/bad-tab-style.gml:1:7
 1 | hello this is bad
   |       ^^^^ accessing this variable is prohibited, instead use `self`

displayed 1 error for testfiles/bad-tab-style.gml
Listing 1. Error output

A game about witches made in less than 2 days for the GM48 game jam.


Figure 1. Gameplay Demo

Designed as a dual language for modding and configuration, Catspeak is a domain-specific language, compiler, and runtime system that resembles the Lisp-family of programming languages. The language is entirely customisable, with only a few primitive constructs, such as variable assignment and control-flow statements. Custom operators and functions are exposed to the Catspeak virtual machine under the discretion of developers, in order to limit how much access a modder has to the game environment.

factorial = fun n {
  if (n <= 1) {
    return 1
  }
  return : factorial (n - 1) * n
}
print : factorial 10 -- 3628800
Listing 1. Recursive functions

Catspeak is implemented in GameMaker Language in order to be stable across many different platforms, and is designed be evaluated over multiple frames in order to avoid freezing the game. In order to achieve this, both the compiler and virtual machine use a flat execution model; that is, no recursive descent parsing or tree-walk interpreters. This enables Catspeak programs to be passively compiled, executed, and paused at any time. Despite this, it is still possible for Catspeak scripts to be compiled and evaluated eagerly within a single step if desired.

for [1, 2].[_] = outer {
  for [3, 4].[_] = inner {
    if (outer == 1) {
      continue 2
    }
    result = inner * outer
    break 2
  }
}
print result -- 6
Listing 2. "Foreach" loops

Inspired by game development frameworks, this was a research project that presents a domain-specific language, compiler, and runtime system that abstracts over some important aspects of game development. The language features a strong functional programming framework that is used to express object-oriented and event-driven programming design patterns. The language is not designed to be state-of-the-art, and there is much that could be improved. Figures 1 and 2 show some demos made using the language.


Figure 1. John Conway's Game of Life

Figure 2. Atari Breakout

The language is expressive enough to represent common Object-Oriented patterns, such as dynamic polymorphism and open recursion. Listing 1 shows a simple Class-like definition for a container that only allows natural numbers. An instance of this collection can then be created by calling the constructor Natural(). The methods get, set, and inc of this object are able to be used, but direct access to the number field is not possible.

let Natural = fun() {
  -- private and public interfaces
  let prv = { .number => 0 };
  let pub = { };
  -- populate the public interface
  pub.get = fun[prv]() {
    ret prv.number;
  };
  pub.set = fun[prv](value) {
    let n = :float(value);
    if n < 0 {
      :error(n ++ " must be >= 0");
    }
    prv.number = n;
  };
  pub.inc = fun[pub]() {
    -- open recursion on public `get` and `set` methods
    pub.set(pub.get() + 1);
  };
  -- return the public interface
  ret pub;
};

let nat = Natural();
nat.set(9);
nat.inc();
:println(nat.get());  -- 10
:println(nat.number); -- none, since `number` is not public
Listing 1. Open recursion on a class-like structure

A collection of scripts that enable functional programming approaches in GameMaker Studio 2. Examples of features supported by this library include iterators, higher-order functions, partial application, and simple monadic operations over lists of nullable values.

A mathematical expression parser, evaluator, and numerical solver. The calculator currently supports common mathematical functions, complex numbers and vectors. An implementation of the hill-climbing algorithm for complex numbers is utilised in order to solve equations containing a single unknown variable.

A blog page and informal CV written using Django, a Python web development framework.

Undergraduate blog
Figure 1. Undergraduate blog

An educational graph theory application for computing common relation operations and graph traversals. A monadic recursive descent parser was written so that graphs encoded in a limited form of the Graphviz DOT script can be imported and exported using the application.

The result of a group project assignment where we were tasked to create a video game with networking and database connectivity. I was responsible for the implementation of the netcode, artificial intelligence of non-player drivers, and physics. Additionally I worked partially on the graphics and system integration.


Figure 1. Gameplay demo

The netcode architecture is client-server, where one user acts as a host to other players. Verification of the physics world is performed on the server-side before being transmitted to all clients. This allows players to collide with each other in real time using simple circle-circle physics intersections. Additionally, the server uses a process similar to boids in order to make decisions about how non-player drivers should follow the road. These decisions are then used to simulate inputs for the AI driver so that it has no technical advantage over other players.


Figure 2. Racing against an AI player

LeJOS Robots designed to follow paths (shown in Figure 1), avoid obstacles (shown in Figure 2), and map the shortest path through a maze. I was responsible for navigation, obstacle avoidance, and path finding.


Figure 1. Following sharp corners

Figure 2. Avoiding obstacles

A tool intended to be used alongside GameMaker Studio 2 which automatically builds extension resources from .gml source files. The program featured three main commands:

  • compile for combining a directory of .gml files into a single file,
  • amend for updating the JavaDoc help information for an extensions,
  • and exmacros for extracting macro information from source files and inserting them into the IDE.

However, lately this has become redundant with the introduction of project templates and local asset packages. So, it's not as useful as it was in the past.

This was a research project that presents an application for editing, traversing, and exporting graph structures using a graphical user interface. The features the application offers include:

  • Inserting and deleting vertices and edges
  • Updating properties of vertices and edges, such as their position, colour, weight, or label
  • Viewing the adjacency matrix of a completed graph (shown in Figure 1)
  • Performing graph traversals, such as depth-first and breadth-first traversals
  • Performing shortest path algorithms between two nodes on a weighted, directed graph (shown in Figure 2)
  • Saving and loading graphs as a special data format
  • Exporting graphs as .png images (shown in Figure 3)
User interface
Figure 1. User interface
Shortest path between two vertices
Figure 2. Shortest path between two vertices
Exporting a graph as a <code>.png</code> image
Figure 3. Exporting a graph as a .png image

No more notable projects!
d /('0 _ 0')\ b

All projects listed are either personal projects, paid work, or notable academic assignments. Although many of the personal projects are not particularly useful, they are a result of technical challenges or interests that I want to showcase.

I've also started participating in the yearly programming challenges of Advent of Code, with my solutions hosted on my GitHub. The goal of my solutions are to use a wide variety of programming languages in order to solve the programming problems. This includes languages I have not yet applied to a practical situation, such as Prolog or Go.