We are currently working on new rules for what content should and shouldn't be allowed on this website, and are looking for feedback! See Esolang:2026 topicality proposal to view and give feedback on the current draft.
COSOL26
| Designed by | User:MxBrahms/User:SirBrahms |
|---|---|
| Appeared in | 2026 |
| Computational class | Turing complete |
| Reference implementation | See External Resources |
| File extension(s) | .cos (Files) / .cosh (Headers) |
The COmmon Stack Based Programming Language (COSOL or COSOL26), is, as the name implies, a stack-based esoteric programming language. It is a (mostly spiritual) successor to the original COSOL22, and as such is not backwards compatible with COSOL22. The general look and feel has however been preserved between standards. The following will outline the general concepts and instructions that make up COSOL.
Please also not that while the language is somewhat stable, the current implementation is mostly a proof of concept and may be reworked entirely in the future. This article describes COSOL26 1.x.
Stacks
COSOL26, like its predecessor, features three main Stacks (which are in turn associated with a specific datatype), and a simple global value, the Stack Index, which is used by the individual instructions for selecting the stacks they operate on. They are called "Global Stacks".
| Stack Index | Type Symbol | Name | Type |
|---|---|---|---|
| 0 | # | mth (Math) | 32 bit integer |
| 1 | $ | str (String) | strings |
| 2 | & | cnd (Conditional) | 32 bit integer, casted to bool |
Newly added are however User Stacks, which can be defined by the user using the following syntax:
<[Type Symbol][Name]>
Where Type Symbol is one of the type symbols above, and Name can be decided freely. So to define a Stack, which contains strings and is called "user1", use the following syntax:
<$user1>
All User Stacks are referred to using Stack Index 3. If a User Stack with the same name and type is defined again, it is instead thought of as a reference to the existing Stack, which is used by some instructions as well.
Literals
COSOL supports defining literals for all three global stacks. These literals are automatically pushed onto their respective stack once encountered in the program.
| Target Stack | Literal Syntax |
|---|---|
| mth | #NUMBER# |
| str | "String" |
| cnd | TRUEor FALSE |
It is currently not possible to define literals for User Stacks.
Blocks and Scope
The language features two types of blocks: Functions, and Loops. Functions that are not defined global do not share a scope with the rest of the program, meaning that it does not have access to User Stacks (and User Stacks only; The Stack Index remains global throughout the program) defined outside it. Conversely, the caller does not have access to user stacks defined within the function either. Loops however inherit the outer scope, and make their User Stacks available to it as well.
Instructions
The following section lists all instructions accepted by COSOL. For ease of comprehension, the list is split into different groups.
General Instructions
| Instruction | Description |
|---|---|
. |
Pops two values off str. The second value is written to the location specified by the top value (stdout for Standard Output). |
_ |
Pops one value off str. If the value is "stdin", one line of input is read from Standard input, and pushed back onto str. If it is a file, that file is opened, and pushed in its entirety to str. |
, |
Deletes the top value from the stack pointed to by the Stack index |
< |
Pops one number off mth. Moves the value FROM the stack pointed at by this number TO the stack pointed at by the Stack Index. |
> |
Moves the top value from the currently selected User Stack to the Global Stack with corresponding type. |
<< |
Moves the top value from the Global Stack with corresponding type onto the selected User Stack |
? |
Entirely clears the stack pointed at by the Stack Index |
/ |
Duplicates the top value of the stack pointed at by the Stack Index |
~ |
Swaps the top two values of the stack pointed at by the Stack Index |
` |
Pops a string off str. Throws that String as an exception |
^ |
Pops a string off str. Calls the function with that string as its name |
' |
Has the same effect as ^, but only calls the function if the top value on cnd is TRUE |
| |
Pops one number off mth and sets the Stack Index to it |
+ |
Pushes the current Stack Index onto mth |
@ |
Pops str and tries to use the value as a path for importing a header file (See Header Files) |
\ |
Pops mth and exits with that exit code. If mth is empty, exits with 0 |
$$ |
Line Comment |
Loops
There are two types of loops; Static Numbered Loops (which simply loop x amount of times) and While Loops. To define which type the next loop encountered in the program will become, use the following instructions:
| Instruction | Effect |
|---|---|
; |
Pops mth. Sets that number of iterations for the next loop, making it a Static Numbered Loop |
;; |
Sets the next loop to be a While Loop |
The loop body itself is defined as follows:
[ INSTRUCTIONS ]
If the next loop is defined to be a While Loop, it is only entered if the top value on cnd is TRUE. If it is not, the Loop is skipped. If cnd is empty, an exception is thrown. After the Loop has been entered, cnd is popped again at the end of the Loop. The loop continues if the value is TRUE. Thus, to define an infinite loop, this syntax could be used:
;; TRUE [ INSTRUCTIONS TRUE ]
Functions
The function body is defined as follows:
{ INSTRUCTIONS }
Note that instructions within a function definition are not executed, unless the function is called.
The above example function would however be assigned the empty string as its name. The following table outlines different options for defining functions with names:
| Instruction | Effect |
|---|---|
: |
Pops str and uses the value as the name for the next function |
:| |
Pops str and uses the value as the name for the next function, and marks that function global |
:! |
Pops str twice. Interprets the bottom value as the function body, and assigns the function name as the top value |
:? |
Has the same effect as :!, but additionally marks the function global |
-> |
Automatically executes the next function block the program encounters if the top value of cnd is TRUE |
If a non-existent function is called, an exception is thrown, unless a function named "^" exists, in which case it is called instead. Functions do not have to be defined at the top level: If for example a function is defined within a function however, it only becomes available once the wrapper function has been executed.
Exceptions
COSOL throws exceptions whenever an unexpected, unrecoverable error happens (e.g. a non-existent function is called and no "^"-function is defined). To catch such errors, use the following instructions:
| Instruction | Effect |
|---|---|
`> |
Defines the next function as an exception handler, which is called whenever an exception occurs. There can only be one exception handler at any given time |
<- |
Defines the next function as safe; If an exception is encountered within it, the exception handler is called instead |
Any exception, if caught, pushes two pieces of information on the stack: first (meaning lower on the stack) a stack trace or context in which the error occurred, and second (higher on the stack) a string more closely describing the error. Note that after an exception is thrown and the exception handler is executed, the old exception handler is destroyed and cannot be reused. For example:
$$ the following is the exception handler (it does nothing)
`> { }
<- { "exception!!"` }
<- { "exception 2!!"` } $$ this will not work, since the original exception handler has gone out of scope.
Math Contexts
Contexts are COSOL's way of getting more out of the limited symbol set. A math context specifically is need for all math and conditional operations, and it is defined as follows:
( INSTRUCTIONS )
Note that for all binary (i.e. two operands) math operations, this formula is used:
stack[top] (OPERATION) stack[top - 1]
| Instruction | Effect |
|---|---|
+ |
Adds the top two values of mth |
- |
Subtracts the top two values of mth |
* |
Multiplies the top two values of mth |
/ |
Divides the top two values of mth |
% |
Performs the modulo-operation on the top two values of mth |
= |
Pushes TRUE if the top two mth values are equal |
! |
Pushes TRUE if the top two mth values are not equal |
< |
Pushes TRUE if mth[top] is less than mth[top - 1] |
> |
Pushes TRUE if mth[top] is greater than mth[top - 1] |
& |
Pushes TRUE if the top two values of cnd are both TRUE |
| |
Pushes TRUE if either of the top two cnd values are TRUE |
String Contexts
String contexts are defined as follows:
$( INSTRUCTIONS )
And there are the following instructions
| Instruction | Effect |
|---|---|
= |
Pushes TRUE to cnd if the top two values of str are equal |
+ |
Concatenates the top two values of str (see Math Context for the binary expression formula) |
> |
Pops mth and chops that number of characters off the top value of str's beginning |
< |
Pops mth and chops that number of characters off the top value of str's end |
^ |
Pops mth and pushes the character at that offset. Does not destroy the original string! |
? |
Pushes the lenght of the top value of str to mth without destroying the aforementioned str value |
Header Files
To safely include code into a source file, the @-Directive is used. It loads the file at a specified path (looking also in /usr/lib/cosol if a file cannot be found elsewhere) and adds all functions defined within the file. It is currently not possible for a Header Function to override a locally defined one.
There is one header-specific instruction, '*': Once encountered, it pops one value off the (header-loader internal) str stack and uses it as a prefix (using the "[prefix].[funcname]"-style) for all functions defined after it. The prefix cannot be reset to nothing.
Standard Library
COSOL26 includes a (currently somewhat sparse) standard library, which is usually installed in /usr/lib/cosol. The following files exist:
- stddup.cosh: For duplicating the top value on the global stacks while preserving the stack index
- stdio.cosh: For basic input and output
- stdmove.cosh: Provides functions for moving values within or between stacks
- stdmath.cosh: Provides math-related functions (currently only for squaring)
- easy.cosh: (Must be included via Preprocessor, see below) translates COSOL's Symbols into human readable text
Preprocessor
In addition to all of the above, COSOL26 also includes a simple C-Style preprocessor, which is mainly based on the "find and replace" principle. All preprocessor directives are applied before any other code is interpreted. The directives are introduced with #! and anything that is not listed as a possible directive below is ignored; thus the the #!-Symbol can also serve as a shebang at the top of script files.
| Directive | Description |
|---|---|
define |
Defines a symbol. If an argument is given, the symbol is defined to translate to the argument. This translation is applied everywhere, including in strings! |
ifdef |
Only includes any code between it and #!endif if the symbol given as its argument is defined |
endif |
Terminates an ifdef block |
| include | Fully includes a file into the source code. Any preprocessor directives defined in the included file are also run again |
Examples
Added below are some simple examples of the language. More can be found in the git repositories (See External Resources).
Cat Program
"stdin" _ $$ take input "stdout" . $$ print it to stdout
Truth Machine
$$ the default function, called if a function does not exist
"^": {
"Please enter either 0 or 1\n" "stdout".
}
$$ called if the user enters a '0'
$$ print 0 and return -> exit
"0": {
"0\n" "stdout".
}
$$ called if the user enters a '1'
$$ print 1 indefinitely
"1": {
TRUE;;[ "1" "stdout" . TRUE ]
}
"stdin" _^ $$ take input and call it
External Resources
The Source Code is available under the terms of the GPL3 (with the exception of the examples shown here, which are released under a CC0 dedication) via the web services below. Note that there is currently no windows-compatibility.