Skip to content

Commit

Permalink
Merge branch 'master' into gh-pages
Browse files Browse the repository at this point in the history
  • Loading branch information
dloscutoff committed Feb 26, 2024
2 parents 7e90ac9 + 3a81f9c commit a796a51
Show file tree
Hide file tree
Showing 9 changed files with 280 additions and 96 deletions.
5 changes: 4 additions & 1 deletion BitCycle/bitcycle.css
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,12 @@
.green {
color: #0c0;
}
.hide {
display: none;
}
h1 {
text-align: center;
font-family: Consolas, 'Courier New' ,monospace;
font-family: Consolas, 'Courier New', monospace;
}
a {
text-decoration: none;
Expand Down
115 changes: 87 additions & 28 deletions BitCycle/bitcycle.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ const ZERO_BIT = 1;
const ONE_BIT = 2;

const BIT_SHAPE_RADIUS = 7;
const GRID_SQUARE_SIZE = 16;
const GRID_SQUARE_SIZE = 24;
const GRID_FONT_SIZE = 14;

const DEFAULT_TICKS_PER_SECOND = 10;
const DEFAULT_FRAMES_PER_TICK = 1;

const BLUE = "#ABF";
const GREEN = "#6E6";
const TEAL = "#4A9";
Expand Down Expand Up @@ -177,14 +180,14 @@ function Source(x, y, inputString, ioFormat) {
} else if (ioFormat === "signed") {
inputString = inputString.split(",").map(intToSignedUnary).join("0");
}
this.queue = inputString.split("");
this.queue = inputString.split("").map(value => new Bit(this.x, this.y, EAST, value));
this.open = (this.queue.length > 0);
}

Source.prototype.tick = function() {
var outBit = null;
if (this.open) {
outBit = new Bit(this.x, this.y, EAST, this.queue.shift());
outBit = this.queue.shift();
if (this.queue.length === 0) {
this.open = false;
}
Expand Down Expand Up @@ -255,10 +258,12 @@ Device.prototype.toString = function() {
}

// Define Program class
function Program(codeLines, inputLines, speed, ioFormat, expand) {
function Program(codeLines, inputLines, ticksPerSecond, ioFormat, expand) {
var sinkNumber = 0;

this.setSpeed(speed);
const framesPerTick = DEFAULT_FRAMES_PER_TICK; // TODO: let user set this
this.setSpeed(ticksPerSecond, framesPerTick);
this.frame = 0;
this.done = false;
this.paused = true;

Expand Down Expand Up @@ -344,18 +349,34 @@ function Program(codeLines, inputLines, speed, ioFormat, expand) {
}
}

Program.prototype.setSpeed = function(speed) {
this.speed = +speed || 10;
Program.prototype.setSpeed = function(ticksPerSecond, framesPerTick) {
this.ticksPerSecond = +ticksPerSecond || this.ticksPerSecond || DEFAULT_TICKS_PER_SECOND;
this.framesPerTick = +framesPerTick || this.framesPerTick || DEFAULT_FRAMES_PER_TICK;
this.speed = this.ticksPerSecond * this.framesPerTick;
}

Program.prototype.run = function() {
this.paused = false;
this.tick();
this.step();
if (!this.done) {
this.timeout = window.setTimeout(this.run.bind(this), 1000 / this.speed);
}
}

Program.prototype.step = function() {
// Step one frame forward
this.frame++;

if (this.frame === this.framesPerTick) {
// Move the program state forward one tick and display the current
// state of the playfield
this.tick();
} else {
// Display the current state of the playfield
this.displayPlayfield();
}
}

Program.prototype.tick = function() {
if (this.done) {
haltProgram();
Expand Down Expand Up @@ -539,7 +560,8 @@ Program.prototype.tick = function() {
}

// Display the current state of the playfield
displaySource(this.grid, this.activeBits);
this.frame = 0;
this.displayPlayfield();
}

Program.prototype.reset = function() {
Expand Down Expand Up @@ -578,21 +600,26 @@ Program.prototype.halt = function() {
}
}

function displaySource(grid, activeBits) {
Program.prototype.displayPlayfield = function() {
clearCanvas();
// Attach active bits to the devices at those coordinates
for (var b = 0; b < activeBits.length; b++) {
var bit = activeBits[b];
grid[bit.y][bit.x].bitCode |= (bit.value ? ONE_BIT : ZERO_BIT);
}
// Display active bits and devices
for (var y = 0; y < grid.length; y++) {
var row = grid[y];
// Display all zero bits on the playfield first
for (var b = 0; b < this.activeBits.length; b++) {
if (this.activeBits[b].value === 0) {
drawBitOffset(this.activeBits[b], this.frame / this.framesPerTick );
}
}
// Then display all one bits on the playfield
for (var b = 0; b < this.activeBits.length; b++) {
if (this.activeBits[b].value === 1) {
drawBitOffset(this.activeBits[b], this.frame / this.framesPerTick );
}
}
// Then display devices
for (var y = 0; y < this.grid.length; y++) {
var row = this.grid[y];
for (var x = 0; x < row.length; x++) {
var device = row[x];
drawBitsAt(device.bitCode, x, y);
drawDeviceAt(device, x, y);
device.bitCode = 0;
}
}
}
Expand All @@ -603,17 +630,24 @@ function clearCanvas() {
}
}

function drawBitsAt(bitCode, x, y) {
function drawBitOffset(bit, offsetAmount) {
var x = bit.x + dx(bit.direction) * offsetAmount;
var y = bit.y + dy(bit.direction) * offsetAmount;
var bitCode = (bit.value ? ONE_BIT : ZERO_BIT);
drawBitsAt(bitCode, x, y);
}

function drawBitsAt(bitCode, x, y, scale=1) {
if (bitCode > 0) {
var centerX = (x + 0.5) * GRID_SQUARE_SIZE;
var centerY = (y + 0.5) * GRID_SQUARE_SIZE;
if (bitCode === ZERO_BIT) {
drawCircle(centerX, centerY, BIT_SHAPE_RADIUS, BLUE);
drawCircle(centerX, centerY, BIT_SHAPE_RADIUS * scale, BLUE);
} else if (bitCode === ONE_BIT) {
drawDiamond(centerX, centerY, BIT_SHAPE_RADIUS, GREEN);
drawDiamond(centerX, centerY, BIT_SHAPE_RADIUS * scale, GREEN);
} else { // Both a zero and a one bit
drawCircle(centerX, centerY, BIT_SHAPE_RADIUS, BLUE);
drawDiamond(centerX, centerY, BIT_SHAPE_RADIUS, GREEN);
drawCircle(centerX, centerY, BIT_SHAPE_RADIUS * scale, BLUE);
drawDiamond(centerX, centerY, BIT_SHAPE_RADIUS * scale, GREEN);
}
}
}
Expand All @@ -640,6 +674,18 @@ function drawDeviceAt(device, x, y) {
var textY = (y + 0.5) * GRID_SQUARE_SIZE + 0.25 * GRID_FONT_SIZE;
context.fillStyle = BLACK;
context.fillText(device.toString(), textX, textY);

if (device instanceof Collector || device instanceof Source) {
for (let i = 0; i < Math.min(device.queue.length, 6); i++) {
let bit = device.queue[i];
drawBitsAt(
(bit.value ? ONE_BIT : ZERO_BIT),
x - (1 / 7 + i / 7) + 0.5,
y + 1 / 7 - 0.5,
0.25
);
}
}
}

function urlDecode(value) {
Expand Down Expand Up @@ -777,6 +823,19 @@ function hideEditor() {
executionControls.style.display = "block";
}

function toggleCheatSheet() {
var cheatSheet = document.getElementById('cheat-sheet'),
indicator = document.getElementById('cheat-sheet-indicator');

if (cheatSheet.classList.contains("hide")) {
cheatSheet.classList.remove("hide");
indicator.innerText = "-";
} else {
cheatSheet.classList.add("hide");
indicator.innerText = "+";
}
}

function loadProgram() {
var sourceCode = document.getElementById('source'),
ticksPerSecond = document.getElementById('ticks-per-second'),
Expand All @@ -803,7 +862,7 @@ function loadProgram() {
context.font = "bold " + GRID_FONT_SIZE + "px Courier New";

// Display the current state of the playfield
displaySource(program.grid, program.activeBits);
program.displayPlayfield();

runPause.style.display = "block";
step.style.display = "block";
Expand Down Expand Up @@ -853,7 +912,7 @@ function runPauseBtnClick() {
if (program !== null && !program.done) {
if (program.paused) {
var ticksPerSecond = document.getElementById('ticks-per-second');
program.setSpeed(ticksPerSecond.innerText); // TBD: is innerText the best way to do this?
program.setSpeed(ticksPerSecond.innerText);
runPause.value = "Pause";
program.run();
} else {
Expand All @@ -867,7 +926,7 @@ function stepBtnClick() {
var runPause = document.getElementById('run-pause');
if (program !== null && !program.done) {
program.pause();
program.tick();
program.step();
runPause.value = "Run";
}
}
Expand Down
38 changes: 37 additions & 1 deletion BitCycle/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
<head>
<title>BitCycle interpreter</title>
<!--
Designed and written 2017, 2020-21 by D. Loscutoff
Designed and written 2017, 2020-21, 2024 by D. Loscutoff
With contributions from Mousetail (https://github.com/mousetail)
-->
<link rel="stylesheet" type="text/css" href="bitcycle.css">
</head>
Expand Down Expand Up @@ -50,6 +51,41 @@ <h1><a href="https://github.com/dloscutoff/Esolangs/tree/master/BitCycle" target
</div>
</div>
</div>
<h3><a href="#" class="blue" onclick="toggleCheatSheet()">Cheat Sheet <code id="cheat-sheet-indicator">+</code></a></h2>
<div id="cheat-sheet" class="toggle hide">
<p>
<code>&lt;</code>, <code>^</code>, <code>&gt;</code>, and <code>v</code>
change a bit's direction unconditionally
</p>
<p>
<code>+</code> changes a bit's direction conditionally:
<code>0</code> turns left; <code>1</code> turns right
</p>
<p>
<code>/</code> and <code>\</code> (splitters) deflect first bit,
pass others straight through
</p>
<p>
<code>=</code> (switch) changes form based on first bit:
if <code>0</code>, becomes <code>{</code> and sends following bits west;
if <code>1</code>, becomes <code>}</code> and sends following bits east
</p>
<p>
<code>A</code>-<code>U</code> and <code>W</code>-<code>Z</code> (collectors)
store bits in a queue when closed and emit them, moving east, when open
</p>
<p><code>?</code> (source) emits bits from input, moving east</p>
<p><code>!</code> (sink) outputs bits</p>
<p>
<code>~</code> (dupneg) copies a bit;
original copy turns right, inverted copy turns left
</p>
<p>
<code>0</code> and <code>1</code> create a bit at the start of the
program, moving east
</p>
<p><code>@</code> halts program</p>
</div>
<script src="bitcycle.js"></script>
</body>
</html>
2 changes: 1 addition & 1 deletion Exceptionally/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ The interpreter supports two flags. The `-V` or `--version` flag prints the vers

> whython exceptionally.why -q program.exc

If you don't have Whython installed, you can run it at [Attempt This Online](https://ato.pxeger.com/about). Here is [an adapted version of the Exceptionally interpreter](https://staging.ato.pxeger.com/run?1=nVjNcts2EJ5edeojoHBTk7ak2IfOdOgorus6Hc-ktseq0-nQigamIAkJSTAgaElV3RfpJZdOn6Avk6fpAiTAP8lJyoMp7C7259sfgP7rn8V8Jec8fv_hy39ZlHAhkaCd4le6SjudV2fXw_PLCzRA-KD_bf8Adzo_nF-cXP8GlHUHwYP3sYcwmUxwN1_31DrN7sx6T62jLDTrp2o9Yfdm_UTzud3_Wq0TvjDrrlpPBY8kNyRPkZikkSH42mbIAqoEDXVkqeXW77U2FltzO4oQ8CyWhvKH3paEzFK-VpQ3nMWG8I32kTBhCH9qEJKEWsUPnc7p5c9XJ9fnQ41fgdZACdJ3GbF4PFOUkKapITxXhJmgRFJRKrupo36ihLgAawjtoCimEY9Z4KGTNGAsFznVkc2tjz9q4PnCRnGmfQlpZE2_0OiELDGEn7Qv1CJxrpEvsXqZO29VXhZuWc_xtaIIEs8qSRhqhKWVuVHrzBp9pf26LyH6VREWgiQlHC9uLk6HJRyq_jwUkuhuQtCyi1YeWqJ9tCoUqHJssXuWraqzxd6zbFWsLfbTcjffYPuJZRel25AIWSodDYujCK5bSOuqbmrzVyMTiK3xtoxXE2qbXPqe1aM7oMnvA5EunZXxJe-KlpQml1J5p7SkNLmU0t3TEFr1FdVZGhndUA0ZX72M10WDbUh0iVDeWy2RwcAmRPdaS-CZ5ZvWa4k8LytCdVHJz6vpEB1D3CFfUOGYkPLuytNtoFftVdvre17vcAS7e0vjApU1ERYnmbRK8_6q8jHOoUxhcNMJIOoiNkUsZXEqSRzoGoN-cxENU4qsVKHPdGfupq-XBs6s4StgnceZQS7KOHVzVgX95ci06oROkQSlacJC6gR8Ql1P8yxxMg5ZTFNoZz_fpYRgpV79EBxnieNqBkSliRCWkOmCybmDj7GLuGjTj3BhRz2CMIh8uIolWZ4JwYUzxVeCzwSJUEDimEt0R2csRmovWitl_sHoAedmF3PwUlsoNYIrEfIGcGL2IyIDMLjb34NxXAnQPJVw_KgPJey43qgeWCkaSxZntGqmcAaqAOHjI1zXvYNO8y0sniGCEkHvGc9SpBCtCXLIF5EA1MAo3Orj4TbvwBmFVB2Iz4AYQi8ANt4YhM0DN5JxxVO4XSijJQVIRzgvY0Os7W_WlK86a3-Aphitq7ofELb7lLYmqENVSIhPAdKYLtpoNu3089nk4Eo8AY8iAhG3AddJzZmQ1PxGVfcAjoEkhDGkMBB0pgrtSerAry5aEzF7cDEcMflGv1A1qgRUN1BeRLYbOYQTrW2h3PlxKzePR6GVFnGUBm4-IQKV9Cu8XXMi4EZidG5XsX5ERQGx1vGIiodHVNj4QNcjKr56RAVL1H74u9_2pFmim7rtbJnQAEa7MdhFUzirJ15rnqnnow2_g66IABtyTo3C3RSBX1lEY7l9Dgo8PnaOvdvJ3m3fPb6d7G8eijvoPJZ0RoUa3tOQEwldBucuCWtixh64GvVngmfNmbSDbuDaItKACwplOGEBoJnqvp0Rye4pirPojormIDOKa2fGGLvtwVZxATsYkmO3Cgq5g-MV9nXVl48LTNyswSY6Pun9PtoKygWJ6KcDsMnALvZf49vb0R7e3WJjCJmG0-Kz4d40KC-43dNFcNSTLJQpkly1AdwmGrhXoaz1iQqjVR-QpHgFut5SOJdJinSAFMo6fQtNIudQMpGSCOZEECh8kf6fY1ePcmhBxmOkDgpnbXqyP-UCbDrg9cB47j50KwnedtxUdGpZQWUm4pZ4fjkSWayvRV30LmNUDl4QwLlIWlIcoIPmFaq4Qa1K0OiSBg7Oryq_iIx6SH1DOS_PL86GPktG7pEaLQPk6AFz6ML0hS-3nO8WX1b20d9XDdoaa1m45xVeNfhqgAHzoEVWmQZ6g_yQx0CXAU1k7V6lrgoaig0jr9Mp0iowxn9nctr77n3--vDFJZA6HVAwHsfQRuOxnrjjcURYPB4Xg9ckUl030xUc3GJ2rwaguV-WfDWy7aq4gDm490r3eu8eyg3SWx0Y-UGk5rAKCZgkDFdoXfwTpTp8lWG6hA-kA_eT7b7L7WpgqlY1AYJRObdEu7-f8MRYqfev2afLLa_SeiG6BbwFvv8B). Put your Exceptionally code in the Code box, your input in the Input box, and click Execute. If you want to use a flag, put it in the Arguments box in this format: `["-q"]`.
If you don't have Whython installed, you can run it at [Attempt This Online](https://ato.pxeger.com/about). Here is [an adapted version of the Exceptionally interpreter](https://ato.pxeger.com/run?1=nVhbcxs1FB5e_cRPEAolu4ntJg_MMJuaUELKZKYkmZiUYTauR7FlW3Rv1WpjGxP-CC99YfhHPPTXcI52pb3Facs-xKujc_3ORdr89c9ysVaLOHr3_vN_RZjEUhHJO8Vbuk47nVenV8Ozi3MyIPSg_3X_gHY635-dP7_6FSibDoGH7lOPUDad0m6-7uE6zW7Neg_XYRaY9VNcT8WdWT_R-7GVf43rJF6adRfXMxmHKjYkD0lC8dAQfG0zEBOOjIY6stRS9DutTUTW3A4SJnEWKUP5Q4slgbCUL5HyWywiQ_hK-8iENIQ_NQhJwq3i-07n5OKny-dXZ0ONX4HWABn524xZPJ4hJeBpagjfImEuOVNclsqu66g_1wbTiRE60WEsrEM_aJTjpXX5VBsOeGjtvNBQBCIxhB-1YW7DPtMwl8C8zD21Ki9wHcupdZNeIUWyaF5BfKjhVJbnGteZNfpK-3VX4vELEpaSJWXsL67PT4Zl7FhsHglYeDtlZNUla4-syD5ZFwqw9lrbPbuNpdja3rPbWJmt7aeldPyA7Sd2u6jTBkcgUuVoWBwkuG7BrUu4qc1fj0wgtqDbPF6NqW1y5XtWjy735n4fiHzlrI0veQu0uDS55MrbosWlySWXbpUG07qPVGdleHT3NHh8_DFeF930QKJLhPJGarEMBjYhurFaDM_svumzFsu3lgW7zCNQ56ZCsKtK_ry6Dskx4BDESy4dE2LebXn6TSqw3Wqyvuf1Dkcg3VsZl7iqsYgoyZRVCu-13URChwKs4CAxGvKerHJRmsOfwmTnU2B3iZgRkYooVSya6LqEHnUJD1JOLFehz3R0HoqvlyYFWSMeyE-ORQb5K7HQDV1l9Fcj095TPiMKlKaJCLgziafc9fSeJU7HgYh4CiPAz6WQCVb40w_AcZE4rt6AqDQRwpIqXQq1cOgx1ei06Ee0sIOPZAIiH64jxVanUsbSmdFLGc8lC8mERVGsyC2fi4igLNmgMv9gdE9zs8sFeKktlBrBlZB4AzhS-yFTEzC429-jXVIJ0DyVcPywD2XvuN6oHljJGikRZbxqpnAGKoXQ4yNa171DTnIREc0Jg3rhdyLOUoKI1hhjyBdTANTAKNzq4-E278AZRKoOxCdADKEXABtvDMLmgSvLuOIpXD_QaEkB0hHNy9gQa_LNmvKx-_YHZEbJpqr7nlArh9qaoA6xkEg8A0gjvmyj2bTTz-eZQyvxTOIwZBBxG3Cd1HwTkppfueoewNGRBDC6EAPJ51hoT1IH3rpkw-T83qVwLOWCfqFqVAmobqC8qWw3cginYNtCKflhK9ePR6GVFnGUBq4_IgJM-iXdrjmfkYXO7So2j6goINY6HlFx_4gKGx_oekTFF4-oEAnKw9_9tifNEn2o205XCZ_AaDcGu2QG5_vUa80zfD7Y8DvkkkmwoRbcKNxNCfiVhTxS2-egpONj59i7me7d9N3jm-n-w0Nxh5xFis-5xOE9C2KmoMvgrGZBjc3YA1fD_lzGWXMm7ZBruOrIdBJLDmU4FRNAM9V9O2dK3HESZeEtl81BZhTXzowxdduDreICdSgkx4pKDrmD4xXkuvhp5MImbdZgEx2f9X4fbQXlnIX84wF4yMAu9V_Tm5vRHt3dYmMImYbT4pPhfmhQnsdWpkvgqGdZoFKiYmwDuE00cK9CWesTDKNVH5CkaA263nA4l1lKdIAcyjp9A02iFlAyIXJMFkwyKHyZ_p9jV49yaEERRwQPCmdjerI_iyXYdMDrgfHcve9WErztuKno1LySq0xGLfb8ciSzSF-LuuRtJrgavGCAc5G0pDhAB80rVHGDWpeg8RWfODS_qvwsM-4R_O5yXp6dnw59kYzcIxwtA-LoAXPowvSFr7183y2-xuyjv8katA3VvNQzXjX2cYDB5kGLjJkGeoN8n8fAVxOeqNq9Cq8KGooHRl6nU6RVUkr_ztSs9827_Of9ZxdA6nRAwXgcQRuNx3rijschE9F4XAxek0i8bqZrOLjl_A4HoLlflvs4su2quIA5tPdK93rvDsoN0lsdGPlBhHMYQ4JNFgRrsin-y1IdvmiYr-Cj6sD9aLtvc7samKpVTYBgMOeWaOX7SZwYK_X-NXK63PIqrReiW8Bb4Psf). Put your Exceptionally code in the Code box, your input in the Input box, and click Execute. If you want to use a flag, put it in the Arguments box in this format: `["-q"]`.

## Example programs

Expand Down
2 changes: 1 addition & 1 deletion Exceptionally/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Command | Name | Description
`]` | sliceto | Gets a slice of a string/list ending just before the given index
`@` | find | Finds the first index at which an item/substring appears
`#` | count | Counts the number of occurrences of an item/substring
`|` | split | Splits a string on occurrences of a substring
`\|` | split | Splits a string on occurrences of a substring
`$` | join | Joins a string/list of strings on a given string
`&` | pair | Wraps two values in a two-item list
`~` | append | Appends a value to the right end of a list
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ A 2D language that involves moving bits around a playfield: picture a cross betw
A language that uses exceptions for control flow, inspired by the `?` operator from [Whython](https://www.pxeger.com/2021-09-19-hacking-on-cpython/).

[Github](https://github.com/dloscutoff/Esolangs/tree/master/Exceptionally)
| [Attempt This Online](https://ato.pxeger.com/run?L=exceptionally)
| [Origins](https://codegolf.stackexchange.com/a/242066/16766)

### Ouroboros
Expand All @@ -40,6 +41,7 @@ Each line of code is a loop, which can be shortened or lengthened to achieve con
Generate strings using regular expression syntax.

[Github](https://github.com/dloscutoff/Esolangs/tree/master/Regenerate)
| [Attempt This Online](https://ato.pxeger.com/run?L=regenerate)
| [Replit](https://replit.com/@dloscutoff/regenerate)

### Sisi
Expand Down
32 changes: 30 additions & 2 deletions Regenerate/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,10 @@ This feature is particularly useful for taking numbers as program inputs:

Curly braces can evaluate simple arithmetic expressions:

> python3 regenerate.py -r 'a{3*$~1+1}' 3
aaaaaaaaaa
> python3 regenerate.py -r 'a{3*$~1+1}' 2
aaaaaaa
> python3 regenerate.py -r 'a{3*($~1+1)}' 2
aaaaaaaaa

Use `${...}` to match the result of an arithmetic expression as a string rather than using it as a repetition count:

Expand All @@ -129,6 +131,32 @@ A backreference that starts with `#` instead of `$` gives the length of the back
| Hello, world! |
+---------------+

### Short-circuiting alternation

The `!` operator is similar to `|`, but it matches at most one of its alternatives. The difference only becomes apparent when multiple matches are requested.

> python3 regenerate.py -a -r '$1|x{1,2}'
x
xx
> python3 regenerate.py -a -r '$1!x{1,2}'
x
xx

Here, `|` and `!` behave identically. In both cases, the first alternative (a backreference to a nonexistent group) fails, and the alternation operator tries the second alternative instead.

> python3 regenerate.py -a -r 'x{1,2}|y{1,2}'
x
xx
y
yy
> python3 regenerate.py -a -r 'x{1,2}!y{1,2}'
x
xx

When the first alternative succeeds, `|` goes on to try the second alternative, but `!` stops and does not try the second alternative. (This behavior is inspired by the "cut" from Prolog, which also uses the `!` character.)

Since they are both types of alternation, `|` and `!` have the same precedence and are left-associative: `a!b|c` parses as `a!(b|c)`, and `a|b!c` parses as `a|(b!c)`.

## Example programs

[Hello, world](https://esolangs.org/wiki/Hello,_world!):
Expand Down
Loading

0 comments on commit a796a51

Please sign in to comment.