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;
}