Code

Programming projects that typically have one or more blog posts assoicated with them.

Click & Drag with Vanilla JS

An experiment in implementing clicking and dragging SVG elements using vanilla JavaScript, see Implementing Click & Drag with Vanilla JS for details.

click-drag.js

const svgns = "http://www.w3.org/2000/svg"
const main = document.getElementById("main")

const canvas = document.createElementNS(svgns, "svg")
canvas.setAttribute("width", "100%")
canvas.setAttribute("height", "100%")
canvas.style.border = "solid 2px #242930"

main.appendChild(canvas)

let bbox = canvas.getBoundingClientRect()

const aspectRatio = bbox.width / bbox.height

const height = 100
const width = height * aspectRatio

const viewBox = {minX: 0, minY: 0, width: width, height: height}

const viewBoxStr = [
  viewBox.minX, viewBox.minY, viewBox.width, viewBox.height
].join(" ")

canvas.setAttribute("viewBox", viewBoxStr)

const circle = document.createElementNS(svgns, "circle")
circle.setAttribute("cx", viewBox.width / 2)
circle.setAttribute("cy", viewBox.height / 2)
circle.setAttribute("r", 15)
circle.setAttribute("fill", "#57cc8a")

canvas.appendChild(circle)

let clicked = false

canvas.addEventListener("mousemove", (event) => {

   if (!clicked) {
      return
   }

   bbox = canvas.getBoundingClientRect()

   const x = (event.clientX - bbox.left) / bbox.width
   const y = (event.clientY - bbox.top) / bbox.height

   circle.setAttribute("cx", x * viewBox.width)
   circle.setAttribute("cy", y * viewBox.height)
})

circle.addEventListener("mousedown",  (_) => { clicked = true })
circle.addEventListener("mouseup", (_) => { clicked = false })

canvas.addEventListener("mouseleave", (_) => { clicked = false })

Simple AST

An experiment in representing and evaluating a toy abstract syntax tree using C code, see Evaluating a Simple Abstract Syntax Tree for details.

simple-ast.c

#include <stdio.h>

typedef enum {
    AST_LITERAL,
    AST_PLUS,
    AST_MULTIPLY,
} AstNodeType;

typedef struct _ast {
    /* The type of node this represents e.g.
       a literal, an operator etc. */
    AstNodeType type;

    /* In the case of a literal value, this field
       holds the actual value */
    float value;

    /* In the case of an operator, this pointer
       refers to the left child node */
    struct _ast *left;

    /* In the case of an operator, this pointer
       refers to the right child node */
    struct _ast *right;
} AstNode;

void
ast_print(AstNode *ast, int level)
{
    for (int i = 0; i < level; i++) {
        printf("  ");
    }

switch(ast->type) {
case AST_LITERAL:
    printf("%.2f\n", ast->value);
    break;

case AST_PLUS:
    printf("+\n");
    ast_print(ast->left, level + 1);
    ast_print(ast->right, level + 1);
    break;

    case AST_MULTIPLY:
        printf("*\n");
        ast_print(ast->left, level + 1);
        ast_print(ast->right, level + 1);
        break;
    }
}

float
ast_evaluate(AstNode *ast)
{
    switch(ast->type) {
    case AST_LITERAL:
        return ast->value;

case AST_PLUS: {
    float a = ast_evaluate(ast->left);
    float b = ast_evaluate(ast->right);

    return a + b;
}

    case AST_MULTIPLY: {
        float a = ast_evaluate(ast->left);
        float b = ast_evaluate(ast->right);

        return a * b;
    }
    }
}

int
main()
{
    AstNode one = { .type = AST_LITERAL, .value = 1.0f };
    AstNode two = { .type = AST_LITERAL, .value = 2.0f };
    AstNode three = { .type = AST_LITERAL, .value = 3.0f };

    AstNode plus1 = { .type = AST_PLUS, .left = &one, .right = &two};
    AstNode example1 = { .type = AST_MULTIPLY, .left = &plus1, .right = &three};

    AstNode mul1 = { .type = AST_MULTIPLY, .left = &two, .right = &three};
    AstNode example2 = { .type = AST_PLUS, .left = &one, .right = &mul1};

    float result1 = ast_evaluate(&example1);
    float result2 = ast_evaluate(&example2);

    ast_print(&example1, 0);
    printf("Example 1: %.2f\n", result1);

    ast_print(&example2, 0);
    printf("Example 2: %.2f\n", result2);

    return 0;
}