make the build script use 'include' statement instead of a hard-coded '.asm' file list

This commit is contained in:
2026-05-01 17:22:22 +02:00
parent 6920d10089
commit 92ac475d58
6 changed files with 101 additions and 79 deletions

140
build.ts
View File

@@ -1,4 +1,4 @@
#!/usr/bin/env -S deno run --allow-read --allow-run #!/usr/bin/env -S deno run --allow-read --allow-write --allow-run
import { TextLineStream } from "jsr:@std/streams@1.1.0"; import { TextLineStream } from "jsr:@std/streams@1.1.0";
@@ -9,25 +9,7 @@ import { TextLineStream } from "jsr:@std/streams@1.1.0";
const instructionLength = 4; // in bytes const instructionLength = 4; // in bytes
const rawDataInstructionLengthPrefix = "U32"; const rawDataInstructionLengthPrefix = "U32";
const ppmToAsmScriptPath = './ppmToAsm.ts'; const ppmToAsmScriptPath = "./ppmToAsm.ts";
const asmFilePaths = [
"src/consts/arch.asm",
"src/consts/game.asm",
"src/consts/keyboard.asm",
"src/consts/map.asm",
"src/consts/scene.asm",
"src/consts/screen.asm",
"src/consts/sprites.asm",
"src/init.asm",
"src/main.asm",
"src/lib/game.asm",
"src/lib/drawing.asm",
"src/lib/sprite_rotation.asm",
];
const reservedSpacePath = "src/reserved_space.asm";
const mapPath = "assets/map.ppm"; const mapPath = "assets/map.ppm";
const spritesPath = { const spritesPath = {
@@ -117,7 +99,11 @@ class Minifier {
} }
} }
async function ppmToAsm(mode: "map" | "sprite", label: string, path: string): Promise<string> { async function ppmToAsm(
mode: "map" | "sprite",
label: string,
path: string,
): Promise<string> {
const command = new Deno.Command(ppmToAsmScriptPath, { const command = new Deno.Command(ppmToAsmScriptPath, {
args: [ args: [
instructionLength.toString(), instructionLength.toString(),
@@ -140,62 +126,55 @@ async function ppmToAsm(mode: "map" | "sprite", label: string, path: string): Pr
return decoder.decode(stdout); return decoder.decode(stdout);
} }
async function build(output: WritableStreamDefaultWriter<string>) { async function build(
for (const path of asmFilePaths) { pwd: string,
const file = await Deno.open(path); path: string,
const readable = file.readable.pipeThrough(new TextDecoderStream()) output: WritableStreamDefaultWriter<string>,
.pipeThrough(new TextLineStream()); ) {
const includeExpressionRegex = /^\s*include\s+([^\s;]+)/;
await output.write(` const file = await Deno.open(`${pwd}/${path}`);
;/******************************* const readable = file.readable.pipeThrough(new TextDecoderStream())
;* ${path} .pipeThrough(new TextLineStream());
;*******************************/
`);
for await (const line of readable) { for await (const line of readable) {
if (!line.startsWith("include ")) { const match = line.match(includeExpressionRegex);
await output.write(`${line}\n`); if (match === null) {
} await output.write(`${line}\n`);
continue;
} }
await build(pwd, `${match[1]}.asm`, output);
} }
const asmRawRepresentations = await Promise.all([
ppmToAsm("map", "map", mapPath),
...Object.entries(spritesPath).map(([label, path]) => ppmToAsm("sprite", label, path)),
]);
await output.write(asmRawRepresentations.join("\n\n"));
await output.write(`
;
; RESERVED RAM SPACE
;
`);
await output.write(await Deno.readTextFile(reservedSpacePath));
await output.close();
} }
function printUsage(into: (message: string) => void) { function printUsage(into: (message: string) => void) {
into(`Usage: into(`Usage:
\tbuild.ts [--minify] \tbuild.ts [options...] {file}
\t\tMerge the hardcoded files and output the result to stdout. The "--minify" option can be used to strip the result of all comments, leading/trailing double whitespaces, empty lines and use the more compact raw data representation. \t\tRead the given file and recursively include other '.asm' files to produce a single output.
\tbuild.ts --help \tbuild.ts --help
\t\tPrint this message`); \t\tPrint this message
Options:
\t--minify\tWhen used, the result will be stripped of all comments, leading/trailing double whitespaces, empty lines and use the more compact raw data representation.
\t--ppm \tWhen used, the hardcoded ppm files will be translated to their matching Symfony assembly reprensentation into src/dist.`);
} }
/** /**
* SCRIPT * SCRIPT
*/ */
if (Deno.args.length > 1) { if (Deno.args.length < 1) {
printUsage(console.error); printUsage(console.error);
Deno.exit(1); Deno.exit(1);
} }
let minify = false; let minify = false;
if (Deno.args.length === 1) { let convertPPM = false;
switch (Deno.args[0]) { let path: string | undefined = undefined;
Deno.args.forEach((arg, index) => {
switch (arg) {
case "--help": case "--help":
printUsage(console.log); printUsage(console.log);
Deno.exit(0); Deno.exit(0);
@@ -203,11 +182,42 @@ if (Deno.args.length === 1) {
case "--minify": case "--minify":
minify = true; minify = true;
break; break;
case "--ppm":
convertPPM = true;
break;
default: default:
printUsage(console.error); if (index !== Deno.args.length - 1) {
Deno.exit(1); printUsage(console.error);
Deno.exit(1);
}
path = arg;
break; break;
} }
});
if (path === undefined) {
printUsage(console.error);
Deno.exit(1);
}
if (convertPPM) {
await Deno.mkdir(`${Deno.cwd()}/src/dist`, { recursive: true });
const mapPromise = async () => {
const assembly = await ppmToAsm("map", "map", mapPath);
await Deno.writeTextFile(`${Deno.cwd()}/src/dist/map.asm`, assembly);
};
const spritePromises = Object.entries(spritesPath).map(async ([label, path]) => {
const assembly = await ppmToAsm("sprite", label, path);
const filename = path.split("/").pop()?.split('.')[0];
await Deno.writeTextFile(`${Deno.cwd()}/src/dist/${filename}.asm`, assembly);
});
await Promise.all([
mapPromise(),
...spritePromises,
]);
} }
const encoder = new TextEncoder(); const encoder = new TextEncoder();
@@ -217,9 +227,9 @@ const stdoutWritable = new WritableStream<string>({
}, },
}); });
if (minify) { const writer = minify
const minifier = new Minifier(stdoutWritable); ? (new Minifier(stdoutWritable)).stream.writable.getWriter()
await build(minifier.stream.writable.getWriter()); : stdoutWritable.getWriter();
} else {
await build(stdoutWritable.getWriter()); await build(`${Deno.cwd()}/src`, path, writer);
} await writer.close();

View File

@@ -43,7 +43,10 @@ Bundle all `.asm` and `.ppm` files and output the (optionaly minified) result.
Usage example: Usage example:
```sh ```sh
./build.ts --minify > pacman.asm ./build.ts --minify main.asm > pacman.asm
# To beforehand convert all ppm files
./build.ts --ppm --minify main.asm > pacman.asm
``` ```
## Documentation ## Documentation

View File

@@ -1,11 +1,4 @@
include ../consts/offsets ; /* Draw the whole map (fill the screen memory with the values of the sprites based on the map)
include ../consts/map
include ../consts/screen
include ../consts/scene
include ../consts/sprites
include sprite_rotation
; /* Draw the whole (fill the screen memory with the values of the sprites based on the map)
; Inputs: ; Inputs:

View File

@@ -1,4 +1,3 @@
; /* Return the tile address from the given map coordinate ; /* Return the tile address from the given map coordinate
; Inputs: ; Inputs:

View File

@@ -1,7 +1,3 @@
include ../consts/offsets
include ../consts/map
include ../consts/sprites
; /* Return the sprite id and rotation for the given map coordinates ; /* Return the sprite id and rotation for the given map coordinates
; Inputs: ; Inputs:

View File

@@ -1,4 +1,10 @@
include consts/arch
include consts/game
include consts/keyboard
include consts/map
include consts/scene
include consts/screen include consts/screen
include consts/sprites
include init include init
@@ -347,4 +353,19 @@ game_loop:
jmp game_loop jmp game_loop
include lib/game
include lib/drawing include lib/drawing
include lib/sprite_rotation
include dist/empty
include dist/placeholder
include dist/wall_end
include dist/wall_straight
include dist/wall_corner
include dist/robot
include dist/ghost
include dist/coin
include dist/map
include reserved_space