Documentation

This documentation provides an in-depth guide to the Ulto programming language. Use the navigation links below to explore detailed sections on Variables and Data, Control Structures, and Reversibility in Ulto. Each section includes grammar rules, code examples, and comprehensive descriptions to help you understand the key features of the language.

For detailed docstring for the codebase you can visit on the link below

Reversibility

One of the defining features of the Ulto programming language is its support for reversible computing. Reversibility allows the program's state to be traced back to previous states, providing a powerful mechanism for debugging, rollback, and state management. This is achieved primarily through the rev and revtrace tokens.

1. The `rev` Token

The rev token enables the reversal of a variable's state to its immediately previous value. This operation is sequential, ensuring that the program can only be reversed in the exact order the operations were performed, preserving the integrity of the execution flow.

Example: Using `rev`

x = 10
x += 5
print(x)  # Outputs: 15
rev x
print(x)  # Outputs: 10

In this example, the variable x is incremented by 5, and then the rev operation reverts x to its original value of 10.

Grammar Rule: Reverse Statement

reverse
    : REV ID
    ;

This grammar rule defines the structure of a rev statement in Ulto. It shows that the rev keyword is followed by an identifier, which specifies the variable to be reversed.

2. The `revtrace` Token

The revtrace token allows you to view the history of a variable's state over multiple operations. However, unlike rev, revtrace does not revert the variable to a previous state; it only prints the past states for inspection. The actual reversal still requires the use of rev.

Example: Using `revtrace`

x = 5
x += 10
x *= 2
print(x)  # Outputs: 30
revtrace x 2
# Outputs the state 2 steps back: 5
rev x
print(x)  # Outputs: 20 (Reverts one step back to x *= 2)

Here, revtrace x 2 prints the value of x from two operations ago, but rev x only reverts the variable to its previous one at a time. This is done to ensure no variables are destroyed during the process and all reversal are sequential without missing a step to ensuring intergrity for reversibility.

Grammar Rule: Revtrace Statement

revtrace
    : REVTRACE ID NUMBER
    ;

This grammar rule defines the structure of a revtrace statement. It includes the revtrace keyword followed by an identifier and a number, indicating how far back in the history to trace.

3. Preserving State with LogStack

Unlike traditional programming languages, where variable assignment is often destructive (overwriting the previous value), Ulto uses a log stack to preserve every state change. This allows the program to safely reverse operations without losing any information.

Example: Non-destructive Assignment

y = 50
y /= 2
rev y
print(y)  # Outputs: 50

Even though y was divided by 2, the original value is preserved in the log stack. The rev operation restores y to 50.

4. Pruning Operations

To manage memory efficiently, Ulto includes pruning operations that selectively remove older states from the log stack. This ensures that the program doesn't consume excessive memory while still retaining the ability to reverse recent operations.

Example: Pruning in Action

z = 100
z += 25
z -= 10
rev z
print(z)  # Outputs: 115 (reverts the last operation)

Here, rev z reverts the last operation, but older states may be pruned if memory constraints require it. The program ensures that the most recent operations can still be reversed.