AbySS (Advanced-scripting by Symbolic Syntax) is a programming language designed to combine the thrill of casting spells with the power of advanced scripting. AbySS aims to provide an intuitive and symbolically rich syntax that allows developers to interact with their code as if they were performing magic. Whether you're scripting a simple operation or crafting complex systems, AbySS offers a unique and immersive experience.
- Symbolic Syntax: AbySS emphasizes a symbolically intuitive syntax, making the code easy to read and write, while retaining powerful functionality.
- Spellcasting-inspired Programming: The language's design mimics the experience of casting spells, with reserved keywords that evoke a magical theme.
- Interactive Spellcasting: AbySS supports interactive scripting through an interpreter, allowing real-time execution and feedback.
- Structured Sorcery: AbySS encourages structured programming, combining the flexibility of scripting with the rigor of structured code.
- VSCode Extension: Syntax highlighting, code completion, and snippets are available through the AbySS Codex Familiar VSCode extension.
You can install AbySS from crates.io using Cargo:
cargo install abyss-lang
Alternatively, you can install AbySS by cloning the repository and building it locally. cargo-llvm-cov
is supported for test coverage analysis.
git clone https://github.com/your-repository/abyss.git
cd abyss
cargo install --path .
For test coverage with cargo-llvm-cov
, install the tool as follows:
rustup component add llvm-tools-preview
cargo install cargo-llvm-cov
To start using AbySS, you can either enter the interactive interpreter mode or run .aby
script files.
You can start the AbySS interpreter with the following command:
abyss cast
To run a .aby
script file, use the following command:
abyss invoke <script.aby>
AbySS provides a built-in code formatter that helps maintain consistent code style across your scripts. To format your .aby
scripts, use the following command:
abyss align <script.aby>
This command automatically formats your code according to the language's style guidelines.
AbySS uses a symbolic and intuitive syntax inspired by magical themes. Below are some of the core elements of the language.
- Comments: Comments in AbySS are marked with
//
for single-line comments and/* */
for multi-line comments.
// This is a single-line comment
/*
This is a multi-line comment
*/
AbySS supports the following primitive types:
- arcana: Represents integers (e.g.,
42
,-3
). - aether: Represents floating-point numbers (e.g.,
3.14
,-1.0
). - rune: Represents strings (e.g.,
"Hello, World"
). - omen: Represents boolean values, with
boon
fortrue
andhex
forfalse
. - abyss: Represents the
void
type, indicating no value.
forge x: arcana = 10;
forge pi: aether = 3.14;
forge message: rune = "Hello, AbySS";
forge is_active: omen = boon;
arcana
: Derived from the Latin word for "secret" or "mystery," and also referencing the structured numbering of tarot cards, arcana represents integer values, symbolizing the hidden foundations of calculations in programming.aether
: Inspired by the classical element of ether, believed to fill the universe beyond the terrestrial sphere, aether represents floating-point numbers, capturing the idea of fluid, continuous quantities.rune
: Borrowed from ancient writing systems used in magic, rune represents strings, suggesting the idea that words and symbols hold power in programming as they do in mystical inscriptions.omen
: Drawing from the concept of a prophetic sign, omen represents boolean values. The keywordsboon
andhex
are used fortrue
andfalse
, respectively —boon
originates from Old English, meaning a blessing or benefit, whilehex
comes from Germanic folklore, signifying a curse or spell, reinforcing the mystical theme of the language.abyss
: Symbolizing infinite nothingness, abyss represents the void type, indicating no value is returned, and is also the name of the language, reflecting its philosophy of exploring the depths of symbolic scripting.
In AbySS, type casting is achieved using the trans
keyword.
This allows the conversion of values from one type to another.
trans
: Short for "transformation," trans
enables the conversion of one type into another, reflecting the idea of magical transformations in programming.
forge x: arcana = trans(3.14 as arcana);
Variables are declared using the forge
keyword.
You must explicitly specify the variable type.
forge x: arcana = 42;
forge greeting: rune = "Welcome to AbySS!";
To declare mutable variables, use the morph
keyword with forge
.
forge morph counter: arcana = 10;
counter += 5;
forge
: Derived from the concept of a blacksmith forging items, this keyword represents the creation and declaration of new variables, symbolizing the act of crafting something new.morph
: Inspired by transformation, morph is used to indicate mutable variables that can change their form or value over time.
In AbySS, you can use the oracle
construct to handle conditionals. One approach is to define conditions directly within each pattern, allowing for flexible and readable branching logic.
This method lets you skip a separate conditional statement and write all conditions within the branches themselves.
oracle
: Reflecting the role of an oracle in ancient mythology, this keyword is used for conditionals, where decisions and predictions are made based on input.
forge x: arcana = -5;
oracle {
(x > 0) => unveil("x is positive");
(x < 0) => unveil("x is negative");
_ => unveil("x is zero");
};
In this example, the conditions are written directly within the patterns.
The oracle evaluates each condition in sequence and executes the matching branch.
If no specific conditions are met, the default pattern _
is executed.
Another way to use oracle
is by explicitly writing a condition as part of the oracle
expression, which can be evaluated as an omen
(boolean) value.
oracle (x > 0) {
(boon) => unveil("x is positive");
(hex) => unveil("x is non-positive");
};
Here, the condition x > 0
is evaluated as boon
(true) or hex
(false), and the appropriate branch executes based on this result.
You can also use expressions or assignments within oracle
for more complex evaluations.
forge y: arcana = 42;
oracle (z = y * 2) {
(z > 50) => unveil("z is greater than 50");
(z == 50) => unveil("z equals 50");
_ => unveil("z is less than 50");
};
In this case, z
is assigned the result of y * 2
, and the appropriate branch is chosen based on the computed value of z
.
You can also handle multiple conditions within a single oracle construct, allowing for complex branching based on multiple variables.
forge a: arcana = 3;
forge b: arcana = 2;
oracle (a, b) {
(1, 2) => unveil("a is 1 and b is 2");
(3, 2) => unveil("a is 3 and b is 2");
_ => unveil("Other combination");
};
In this example, oracle evaluates multiple conditions (a and b) together and executes the corresponding branch based on their values. If no specific conditions are met, the default pattern _ is used.
This flexibility makes oracle
a powerful tool for creating readable and intuitive branching logic in AbySS.
In AbySS, loops are managed using the orbit
keyword.
This construct allows for both simple and complex loop structures, with additional control provided by the resume
and eject
keywords.
Below, we explore a range of use cases for loops in AbySS, from basic to advanced scenarios.
orbit
: Inspired by the celestial motion of planets, orbit represents loops, where the code revolves around a central task repeatedly until a condition changes.resume
: Reflecting the continuation of interrupted tasks, resume allows the loop to skip the current iteration and move on to the next.eject
: Analogous to an emergency exit or escape mechanism, eject breaks out of loops, terminating the iteration prematurely.
The most basic form of a loop in AbySS iterates over a range of values. In this example, the loop iterates from 0 to 5 (exclusive of 5).
orbit (i = 0..5) {
unveil(i);
}
This loop prints the numbers from 0 to 4 using the unveil
function.
The ..
operator defines a half-open range, which excludes the upper bound.
You can create a closed range loop using the ..=
operator, which includes the upper bound in the iteration.
orbit (i = 0..=10) {
unveil(i);
}
In this loop, the numbers from 0 to 10 (inclusive) are printed.
By omitting the loop parameters, you can create an infinite loop that runs until a certain condition is met.
The loop can be terminated using the eject
keyword, which breaks the loop when the condition is satisfied.
forge morph i: arcana = 0;
orbit {
oracle (i == 100) {
(boon) => eject; // Break the loop when i equals 100
};
i += 1;
};
unveil(i); // Prints 100 after loop termination
This example increments i
in each iteration until it reaches 100, at which point the loop exits.
AbySS allows you to define loops with more than one parameter, making it easier to iterate over multiple ranges simultaneously.
Here's an example where two loop variables, i
and j
, are defined:
orbit (i = 0..3, j = 0..3) {
unveil(i, " ", j);
}
In this loop, i
and j
both iterate over the range from 0 to 2, and each pair of values is printed.
This pattern is useful when you need to perform operations that depend on two or more varying values simultaneously.
The resume
keyword allows you to skip the current iteration of a loop and move on to the next iteration.
This can be used to control the flow of nested loops.
orbit (i = 0..3) {
orbit (j = 0..3) {
oracle (i == j) {
(boon) => resume j; // Skip the iteration when i equals j
};
unveil(i, " ", j);
}
}
In this example, the inner loop skips the iteration whenever i
is equal to j
.
The eject
keyword breaks the loop entirely.
In nested loops, you can specify which loop to break by passing the loop variable as an argument.
orbit (i = 0..3) {
orbit (j = 0..3) {
unveil(i, " ", j);
oracle (i == 2) {
(boon) => eject i; // Break the outer loop when i equals 2
};
}
}
Here, the outer loop breaks entirely when i
equals 2, effectively terminating both the inner and outer loops.
These examples illustrate the flexibility of the orbit
construct in AbySS, which allows for sophisticated looping patterns with easy-to-read syntax.
The ability to control flow with resume
and eject
further enhances the language's expressiveness in handling loops.
In AbySS, functions are defined using the engrave
keyword.
Functions allow you to encapsulate reusable code blocks and return values.
You can define functions with parameters, specify return types, and call these functions within your scripts.
engrave
: Symbolizing the act of carving a magical circle, engrave is used for function definitions, representing the meticulous process of inscribing reusable spells into the code.
Functions are defined using the engrave
keyword, followed by the function name, parameters, optional return type, and the function body enclosed in {}
.
engrave add(a: arcana, b: arcana) -> arcana {
reveal a + b;
};
In this example, the add
function takes two parameters a
and b
of type arcana
(integer), and returns their sum as an arcana
.
You can call a function by using its name followed by parentheses, and pass arguments matching the function's parameters.
forge result: arcana = add(3, 5);
unveil(result); // Outputs: 8
This example calls the add
function with the arguments 3
and 5
, stores the result in the result
variable, and prints it using unveil
.
AbySS allows you to call functions within other function calls, enabling complex operations to be broken down into simpler components.
engrave add_three_numbers(x: arcana, y: arcana, z: arcana) -> arcana {
reveal add(add(x, y), z);
};
forge result: arcana = add_three_numbers(1, 2, 3);
unveil(result); // Outputs: 6
In this example, the add_three_numbers
function calls the add
function twice to sum three numbers.
Functions in AbySS use the reveal
keyword to return values.
If a function does not explicitly return a value, it implicitly returns abyss
.
engrave greet() -> rune {
reveal "Hello, AbySS!";
};
unveil(greet()); // Outputs: Hello, AbySS!
This function greet
returns a rune
(string) and prints it using unveil
.
AbySS supports recursive function calls, allowing functions to call themselves.
engrave factorial(n: arcana) -> arcana {
oracle (n <= 1) {
(boon) => reveal 1;
};
reveal n * factorial(n - 1);
};
forge result: arcana = factorial(5);
unveil(result); // Outputs: 120
This recursive function calculates the factorial of a number.
For output, AbySS uses the unveil
function to print values to the console.
You can pass multiple variables or expressions as arguments, separated by commas.
This allows you to concatenate different elements in the output.
unveil
: Chosen for its metaphorical meaning of revealing something hidden, unveil is used for output operations, making the internal state of the program visible to the user.
unveil("Hello, AbySS");
unveil("x + 42 = ", x + 42);
In the example above, the second unveil
statement prints both the string "x + 42 = "
and the result of the expression x + 42
on the same line.
For input, AbySS provides the summon
function to read user input during script execution.
The summon
function takes a prompt message and an expected type as arguments.
summon
: Represents the act of calling forth something from the user, summon is used for standard input operations. You can specify a prompt and the type of input expected (e.g.,arcana
,aether
,rune
).
forge name: rune = summon("Input your name: ", rune);
forge age: arcana = summon("Input your age: ", arcana);
unveil("Hello, ", name, "! You are ", age, " years old.");
In this example, the user is prompted to enter their name and age.
The inputs are then stored in the name
and age
variables, and both are printed using unveil
.
The AbySS Codex Familiar VSCode extension provides additional support for AbySS development, including:
- Syntax highlighting for keywords, types, constants, and operators.
- Code snippets for common structures like
forge
,unveil
, andoracle
. - Auto-completion for key AbySS constructs.
To install the extension, search for "AbySS Codex Familiar" in the Visual Studio Code Extensions Marketplace, or download it from the GitHub repository.
- Collection Types: Implement collection types such as lists and dictionaries for handling multiple values (Work-in-progress).
- Struct Implementation: Enable the definition and use of custom data structures (TBD).
- Generics Introduction: Introduce generics to allow functions and data structures to be more flexible and reusable with different types (TBD).
- Module System: Introduce the ability to import functions and variables from other files (TBD).
- Error Handling: Implement robust error handling (TBD).
- File I/O: Introduce input functionality and file handling (TBD).
- Standard Library: Develop a standard library with common functions and utilities (TBD).
- Interpreter Enhancements: Improve the interactive interpreter with better real-time feedback, debugging capabilities, and performance optimizations (TBD).
AbySS is open-source software licensed under the MIT License. See the LICENSE file for details.