@8bitscript/system 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/LICENSE +21 -0
  2. package/package.json +18 -0
  3. package/src/index.8bs +118 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 8BitScript contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/package.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "@8bitscript/system",
3
+ "version": "0.1.0",
4
+ "description": "One name per machine, to compare #system() against: `if (#system() == System.C64)`. Both sides are compile-time numbers, so a program branches on the machine without a per-machine file.",
5
+ "license": "MIT",
6
+ "8bitscript": {
7
+ "entry": "./src/index.8bs"
8
+ },
9
+ "files": [
10
+ "src"
11
+ ],
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "scripts": {
16
+ "test": "node --test"
17
+ }
18
+ }
package/src/index.8bs ADDED
@@ -0,0 +1,118 @@
1
+ // @8bitscript/system — the machine a build is for, by name and by fact.
2
+ //
3
+ // import { System, Video, Audio, Input, Storage, Memory } from "@8bitscript/system";
4
+ //
5
+ // if (#system() == System.PET) { ... } // which machine
6
+ // if (Video.SPRITES == 0) { ... } // what it has
7
+ //
8
+ // Everything here is a compile-time number: #system() is the machine this
9
+ // build is for, and #fact(...) is one fact about it, both resolved by
10
+ // 8bitscript before any target toolchain runs (docs/compiler.md, "what
11
+ // 8bitscript resolves and what runs on the machine"), so a comparison is
12
+ // two constants and the branch for another machine, or for hardware this
13
+ // one lacks, costs nothing on it. The compiler's tables are the source of
14
+ // truth — packages/compiler/src/fold's SYSTEMS for the names, its
15
+ // fold/facts.mjs for the fact keys — and test/system.test.mjs holds this
16
+ // file to both.
17
+ //
18
+ // Two rules for using it. First, prefer a fact to the machine's name:
19
+ // `Video.COLUMNS` is right on a machine this file has never heard of, and
20
+ // on a C128 in 80 columns, where `#system() == System.PET` says nothing.
21
+ // Branch on the name for what is genuinely the machine's identity — which
22
+ // title to print — and on a fact for anything a fact could say. Second, a
23
+ // branch is not a conditional import: both arms of an `if` are compiled
24
+ // and linked on every machine, so a machine-only package
25
+ // (`@8bitscript/c64/sprites`) still belongs in a per-machine file, not
26
+ // behind a comparison.
27
+ //
28
+ // The names are the ones `8bs build --target` accepts. The numbers are
29
+ // arbitrary and stable: a machine keeps its number when others are added,
30
+ // so a saved file that records one stays readable.
31
+ export namespace System {
32
+ const WEB: utinyint = 0; // the browser runtime
33
+ const VIC20: utinyint = 1; // Commodore VIC-20
34
+ const C64: utinyint = 2; // Commodore 64
35
+ const PET: utinyint = 3; // Commodore PET
36
+ const C128: utinyint = 4; // Commodore 128
37
+ const ATARI8: utinyint = 5; // Atari 400/800/XL/XE
38
+ const NES: utinyint = 6; // Nintendo Entertainment System
39
+ const CX16: utinyint = 7; // Commander X16
40
+ const MEGA65: utinyint = 8; // MEGA65
41
+ }
42
+
43
+ // The fact sheet. Each const is one #fact(...) — the value the machine
44
+ // package's hardware catalog declares for the stock machine, changed by
45
+ // whatever hardware the build was fitted with (`8bs build c64 --hardware
46
+ // ram=reu512`; docs/packages.md, "the hardware catalog"). A fact is never
47
+ // missing: a machine without hardware sprites says SPRITES 0, and a
48
+ // program's branch on it folds away. A fact is the worst case that
49
+ // matters: SPRITES_PER_LINE is 8 on the NES, not the 64 per frame.
50
+ //
51
+ // Two kinds of fact, and the difference is when it is settled. Most are
52
+ // fixed by the build — the grid, the chip, the RAM the program was linked
53
+ // into — and the const is the truth on every machine the binary runs on.
54
+ // A few name hardware the machine may or may not have when the program
55
+ // runs: a mouse in a port, a REU, banked RAM. For those the const means
56
+ // "this build may use it" — the hardware was chosen for the build, so the
57
+ // capability's detection code is compiled in — and whether it is really
58
+ // there is the capability's answer at run time. A build never fitted with
59
+ // it carries no code for it. The comments mark which is which.
60
+ //
61
+ // With no machine in hand (8bs check, the editor) every fact is its
62
+ // placeholder — 0 or false — and target-dependent, as #system() is.
63
+
64
+ // The display: the text grid the portable `text` draws on, and what the
65
+ // display is made of beyond it.
66
+ export namespace Video {
67
+ const COLUMNS: utinyint = #fact(video.columns); // cells across
68
+ const ROWS: utinyint = #fact(video.rows); // cells down
69
+ const CELL_WIDTH: utinyint = #fact(video.cellWidth); // pixels across one cell
70
+ const CELL_HEIGHT: utinyint = #fact(video.cellHeight); // pixels down one cell
71
+ const PALETTE: usmallint = #fact(video.palette); // colours on screen at once
72
+ const CELL_COLORS: utinyint = #fact(video.cellColors); // colours one cell can hold
73
+ const COLOR_PER_CELL: bool = #fact(video.colorPerCell); // one cell's colour can be set without changing its neighbours'
74
+ const GLYPHS: usmallint = #fact(video.glyphs); // characters redefinable at run time; 0 = fixed font
75
+ const BLOCK_WIDTH: utinyint = #fact(video.blockWidth); // pseudo-pixels across a cell from block glyphs; 0 = none
76
+ const BLOCK_HEIGHT: utinyint = #fact(video.blockHeight); // pseudo-pixels down a cell; 0 = none
77
+ const BITMAP: bool = #fact(video.bitmap); // a pixel-addressable mode exists
78
+ const LAYERS: utinyint = #fact(video.layers); // independent background layers
79
+ const SCROLL: bool = #fact(video.scroll); // hardware fine scroll
80
+ const SPRITES: utinyint = #fact(video.sprites); // hardware sprites in total; 0 = software objects
81
+ const SPRITES_PER_LINE: utinyint = #fact(video.spritesPerLine); // what one scanline can show
82
+ const SPRITE_WIDTH: utinyint = #fact(video.spriteWidth); // pixels across the largest sprite
83
+ const SPRITE_HEIGHT: utinyint = #fact(video.spriteHeight); // pixels down the largest sprite
84
+ const SPRITE_COLORS: utinyint = #fact(video.spriteColors); // colours one sprite can hold
85
+ }
86
+
87
+ // The sound hardware's shape.
88
+ export namespace Audio {
89
+ const VOICES: utinyint = #fact(audio.voices); // voices at once; 0 = no sound
90
+ const NOISE: bool = #fact(audio.noise); // a noise voice
91
+ const ENVELOPE: bool = #fact(audio.envelope); // hardware volume envelopes
92
+ const FILTER: bool = #fact(audio.filter); // a hardware filter
93
+ const PCM: bool = #fact(audio.pcm); // sample playback
94
+ const VOLUME: bool = #fact(audio.volume); // a volume per voice
95
+ const ENTROPY: bool = #fact(audio.entropy); // a hardware random source
96
+ }
97
+
98
+ // The ports, and what this build may find plugged into them.
99
+ export namespace Input {
100
+ const KEYBOARD: bool = #fact(input.keyboard); // a keyboard the program can read
101
+ const JOYSTICKS: utinyint = #fact(input.joysticks); // joystick ports
102
+ const PADS: utinyint = #fact(input.pads); // console controller ports
103
+ const MOUSE: bool = #fact(input.mouse); // run time: this build may use a mouse
104
+ const PADDLES: bool = #fact(input.paddles); // run time: this build may use paddles
105
+ }
106
+
107
+ // Where bytes can outlive the program.
108
+ export namespace Storage {
109
+ const SAVE: bool = #fact(storage.save); // somewhere to persist bytes
110
+ const KIB: usmallint = #fact(storage.kib); // KiB that place holds
111
+ }
112
+
113
+ // What the program was linked into, and what it may reach beyond it.
114
+ export namespace Memory {
115
+ const RAM: usmallint = #fact(memory.ram); // bytes the program is linked to use
116
+ const BANKED: bool = #fact(memory.banked); // run time: this build may use RAM beyond the window
117
+ const BANKED_KIB: usmallint = #fact(memory.bankedKib); // KiB of it the build was fitted with
118
+ }