Cíonom

From Esolang
Jump to navigation Jump to search
Cíonom
Cíonom's logo, an abstract C with an accent inside of it
Cíonom's logo, an abstract C with an accent inside of it
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 pointer
  • v - 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 pointer
  • c - 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.