Cíonom
Paradigm(s) | imperative |
---|---|
Designed by | User:TTG-Emily |
Appeared in | 2022 |
Memory system | Stack-based |
Dimensions | one-dimensional |
Computational class | Unknown |
Major implementations | Official Implementation |
File extension(s) | .cio (Source), .ibc (Bytecode Module), .cbe (Bundled Executable), .cas (Bytecode Assembly) |
Cíonom (\tʃi-o-nom\) is a language which was created as a test of the Genstone C-framework. It was originally called simply Cio
and was designed to be a C-like language. However through its development became a more esoteric language where the only operative structure is a "call".
The name "Cíonom" is entirely made up.
Language Overview
Cíonom itself is neither high-level nor low-level - instead depending entirely on the calls exposed by the packaged library. The default packaged library in the main implementation exposes a native level language interface.
The structure of a Cíonom program is a text file composed of routine declarations and definitions. A routine declaration is composed of a valid identifier followed by a number indicating the parameter count. A routine definition is a routine declaration followed by a block - a set of calls surrounded by :
.
A call is structured similarly to a routine declaration. It consists of the identifier of a previously declared or defined routine, followed by an arbitrary number of numbers acting as the parameters.
A call functions by pushing the parameter literals onto the stack, preceded by an empty entry known as the "reserve space". All the parameters are taken by the callees stack frame and execution resumes either in external code or in another routine. The reserve entry acts as a return value or variable declaration.
Identifiers in Cíonom are arbitrary sequences of non-whitespace, non-:
characters which don't begin with a number.
An example Cíonom program:
bar 1 foo* 1 : bar 0 bar 1 bar 2 bar 3 : main 0 : foo* 5 :
The main implementation has an incomplete sample of the "Simple" challenge page of Rosetta code implemented in Cíonom using the default packaged library.
Hello World
A "Hello, world!" program in Cíonom using the default packaged library of the main implementation:
copy*[+]=c 3 printc* 1 alloc 1 free* 1 main 0 : alloc 14 copy*[+]=c 0 0 72 copy*[+]=c 0 1 101 copy*[+]=c 0 2 108 copy*[+]=c 0 3 108 copy*[+]=c 0 4 111 copy*[+]=c 0 5 44 copy*[+]=c 0 6 32 copy*[+]=c 0 7 119 copy*[+]=c 0 8 111 copy*[+]=c 0 9 114 copy*[+]=c 0 10 108 copy*[+]=c 0 11 100 copy*[+]=c 0 12 33 printc* 0 free* 0 :
Packaged Library
The main Cíonom implementation resolves routine declarations which lack definitions in an external lib cionom-external
- libcionom-external.so
or cionom-external.dll
or others depending on the platform.
The default packaged library under the main Cíonom implementation provides a native-level interface for code with memory operation primitives such as moves or dereferences and raw buffer operations.
The nature of the packaged library therefore also determines the computing class of the language - though given it does involve deferring to external code it could be said that the language itself is incapable of computation.
Typical Usage
The "typical usages" laid out here only really apply to the default packaged lib of the main implementation as no other code with Cíonom in mind exists presently
Stack Indices
As each call in a Cíonom program produces a stack reserve entry (which may contain a "returned" value depending on the routine), each call could be thought of as a variable declaration. Due to the lack of a variable language construct - the program may reference these by their index. For example:
foo 2 : A B C :
In this routine - the reserve entry produced by the call to A
will be at stack index 2 in this routines stack frame. This is because the first two parameters take up indices 0 and 1.
Continuing along B
's reserve entry will be at index 3 and C
's at index 4.
In the case of the default packaged library, routines such as copy=
take in stack indices (as indicated in the documentation by @param [parameter number] The stack index of Foobar
or the like) to perform their operations.
Routine Indices
Similarly to stack indices, routines may be referenced by their ordinal position within the program. So in the following program for example:
foo 2 bar 3 fizz 1 : bar 0 0 0 : buzz : :
foo
would be routine 0, bar
routine 1, fizz
routine 2 and buzz
routine 3.
The default packaged library uses this with routines such as ?
.
Naming Schema
Much of the "look" of Cíonom programs which use the default packaged library is formed by the naming schema used to remove the need for massive routine names. Since Cíonom only reserves the character :
and identifiers beginning with numbers, there is a large amount of flexibility that lead to this naming schema.
The name copy*[+v]=c
(Copy character value into pointer variably indexed) decomposes into:
copy
- The operation to be performed*
- The operation is performed on a pointer[]
- The operation dereferences a pointer[+]
- The operation indexes a pointerv
- This operand is a stack index, not a literal (implied for pointers)=
- Separator according to operation (shows C-style the order in which operands are interpreted)c
- Operands are treated as characters - this implies that the pointer and indexing operations were also treating pointers as character buffers
The name buffcopy*->*+c
(Copy character buffer to pointer indexed) decomposes into:
buffcopy
- The operation to be performed*
- The operation is performed on a pointer->
- Separator according to operation (shows the direction of the copy according to operand ordering)*
- The operation is performed on a pointer+
- The operation applies an offset to a pointerc
- Operands are treated as characters - this implies that the pointer and indexing operations were also treating pointers as character buffers
Bytecode
Cíonom programs processed by the main implementation are emitted in a dense bytecode format. This format is composed of modules consisting of two sections:
====== Header/Routine Table ====== Code ======
Multiple of these bytecode modules can be concatonated - with the entry point in the first file - and the VM will resolve symbols between them.
Header
The header of a Cíonom bytecode file outlines the routines present in the file/imported by the file ordinally as follows (numbers denote the number of bits an element takes up):
====== Reserved - 1 ====== Count - 7 # The number of entries in the routine table ====== Entries ======
Where each entry is formatted as one of the following - for internal routines (i.e. routines defined in the original source):
======
Offset - 32 # The offset into the code section where this routine's bytecode begins. External routines are indicated with an "offset" of 0xFFFFFFFF
======
Symbol # A C-string containing the unmangled name of the routine
======
Code
Routines within the code section are output back-to-back with no metadata or rising/falling edge other than a single terminating 0xFF
signifying a return. Each opcode-operand pairing is 1 byte where the most significant/leftmost bit is the opcode and the remainder of the byte is an operand. Opcode 0 corresponds to a push
and 1 refers to a call
- hence the return byte could be thought of as call 0x7F
. The encoding push 0x7F
is reserved.
The reserve space is part of bytecode emission rather than being a VM feature for simplicity, so in principle a Cíonom implementation could provide some sort of indicator to elide reserve space on a call outside of the specification and still remain bytecode-compatible with the main implementation's VM.
The remaining 7 operand bits for a call
instruction correspond to the index into the routine table for the routine to be called.
The operand bits for a push
instruction correspond to the value to push.