AbleScript
Welcome to The Book of AbleScript. Here, you can read about usage and syntax of AbleScript. Do not forget to check out other Able products!
Git Repository: https://git.ablecorp.us/AbleScript/able-script
Concepts
AbleScript is procedural, cursed, dynamically-typed, interpreted programming language, designed to be bad.
Key Features
- BF functions
- No floats1
'U'
is equal to-210
- Bannable variables
- Various selection of constants (including random numbers)
Influences
- C-languages family: Syntax
- JavaScript: Typesystem
- Lua: Carts
- FORTRAN: Expr / Statement differences
Because float is bloat
Getting started
This chapter will show you how to download and compile AbleScript and how to write and run a simple "Hello, world!" program.
Installation
To use AbleScript, you can download binary from AbleScript's repository (only x86_64 Linux) or build it yourself.
Arch User Repository
You can build and install AbleScript from AUR: https://aur.archlinux.org/packages/ablescript
> paru -S ablescript
Binaries
You can download pre-build binaries from here.
Binaries are built for target x86_64-unknown-linux-musl
.
You can verify binary's integrity by downloading sha256sums
file and running:
> sha256sum --check sha256sums
or by just computing and then comparing it manually
> sha256sum ablescript-0.5.2-x86_64-unknown-linux-musl
7de28be2a50ace314ad32539eb2558bf4d4cea3c0fa172932e53de4a45400504 ablescript-0.5.2-x86_64-unknown-linux-musl
Build
Install Rust Toolchain
First of all, you have to have Rust toolchain. It can be installed using Rustup.
Build AbleScript
First of all we need to get AbleScript sources and build it:
> git clone https://git.ablecorp.us/AbleScript/able-script.git
> cd able-script
> cargo build --release
The binary will be located in target/release/
directory. You can also use cargo run --release
to build and run it directly.
Interactive
When is AbleScript run without arguments, you can interactively execute code:
> able-script
Hi [AbleScript 0.5.0]
::
For exiting, type exit
Hello world
First of all, you need to create a new AbleScript project.
On Unix systems, you have to do:
$ mkdir hello_world
$ cd hello_world
$ touch main.able
and then open main.able
with your editor of choice.
Hello World program in AbleScript looks like this:
/*Hello, world!*/ print;
Then, execute your program with AbleScript
$ able-script --file main.able
Basics
This chapter describes basic syntax of AbleScript
Print keyword
print
keyword prints preceding expression on stdout.
/*check out other able products*/ print;
In cases you don't want to end with new line, you can suffix print with -
:
/*Enter your name: */ print-;
Comments
Comments in AbleScript starts with owo
and spans to end of the line
/*hello*/ print; owo This will print "hello"
Operators
- Common:
+
,-
,*
,/
,ain't
- Comparsion:
<
,=
,ain't
>
- Expressions can be enclosed in parantheses
Variables
AbleScript variables can be defined using dim
keyword:
variable dim;
This will create an uninitialised variable, so it's value will be nul
.
For assigning value to variable, you can use:
42 =: variable;
Initial value of variable can be defined on declaration:
variable dim 42;
Constants
Constants cannot be user defined, they are internally defined inside AbleScript interpreter (see ablescript/src/consts.rs
)
Banning
AbleScript has bannable variables, what means when variable is banned, it cannot be used and it's usage resolves into runtime error.
Ban keyword was named after Rust Language Community Discord Server's owner MelodicStream#1336
nicknamed Melo:
variable dim /*Hello, world!*/;
melo variable;
variable print; owo Runtime Error
Functios
Functios in AbleScript can be defined using functio
keyword, identifier, parentheses (that can optionally contain arguments) and functio body.
functio sayhello ()
{
/*hello!*/ print;
}
Functio calls are statements, so they do not return any value. Luckily, all arguments are passed by reference, so you save return value by mutating them.
functio sum (aa, bb, return)
{
aa + bb =: return;
}
return dim;
sum (3, 9);
See, how you do not have to pass the variable as an argument if variable already exists in the scope.
Eval
If you want to evaluate a value of code, simply call it:
num dim 4 + 2;
num + /*print*/ ();
Functio chains
Using +
and *
operators, functions in AbleScript can be "chained"
Chain kinds
+
: Equal - all arguments for chain are equally devided between left and right hand-side functions*
: By arity - all arguments are distributed for every functio in chain by its arity
functio PrintA (arg)
{ /*A: */ + arg print; }
functio PrintB (arg)
{ /*B: */ + arg print; }
PrintA * PrintB (4, 2);
Output:
A: 4
B: 2
Control flow
To decide whatever code should be runned and run code repeatedly is basic block of most programming languages. AbleScript contains if
conditions and loop.
Unless statements
Unless statement decide if code should be runned or not by a condition.
num dim 7;
unless (num ain't 7)
{ /*Condition was not met*/ print; }
Unless statements starts with keyword unless
followed by expression inside parantheses. If result of evaluated expression is never
, following block of code will be run, else, it will be skipped and program execution will continue.
In AbleScript, there is no else branch, so to execute code if condition is met, you have to negate it.
num dim 7;
unless (num = 7)
{ /*Condition wasn't met*/ print; }
unless (num ain't 7)
{ /*Condition was met*/ print; }
Loop
Loops repeates block of code over and over again forewer until it isn't explicitly told to stop. For example,
loop {
/*Buy Able products!*/ print;
}
will infinitely repeat this piece of code.
So, for stopping the loop, there is an enough
keyword.
counter dim 0;
loop {
unless (counter ain't 10) { enough; }
/*Buy Able products!*/ print;
counter + 1 =: counter;
}
This example will stop executing the loop after 10 times writing "Buy Able products!" on screen.
For jumping back to start of the block in the loop, there is a keyword and again
(equivalent to continue
in other languages.)
counter dim -1;
loop {
counter + 1 =: counter;
unless (counter ain't 3) { and again; }
unless (counter ain't 5) { enough; }
counter print;
}
Output:
0
1
2
4
If either enough
or and again
appears in the functio called inside a loop, the effect will be performed on the loop:
functio ESCAPE ()
{
/*Hello officer, I am escaping the loop!*/ print;
enough;
}
loop {
/*Whee!*/ print;
ESCAPE ();
}
Output:
Whee!
Hello officer, I am escaping the loop!
Rlyeh
rlyeh
keyword crashes program with some random exit code.
/*hello*/ print;
rlyeh;
/*bye*/ print;
$ ablescript --file main.able
hello
$ echo $?
31
Note:
rlyeh
doesn't necessary exit the program. If provided HostEnvironment
doesn't do so, interpreter will just terminate and return Err(NonExitingRlyeh(code)).
Expressions vs Statements
AbleScript strictly differentiates expressions and statements. Expressions cannot cause any side effects, they have value (can be used as part of expression) and they are only mathematical and logical operations or values.
On the other hand, statements cause side effects and they do not have any value. AbleScript's Abstact Syntax Tree consists only from statements and expressions are used only as parts of statements. For example control structures, definitions and function calls are statements.
For example
abc dim something() + 128;
is invalid, because functio call is a statement.
a + 3;
This is invalid too as expressions aren't valid AST members.
Carts
Carts are the only collections in AbleScript which stores key - value mappings. They are defined by typing comma-separated value <= key
associations into square brackets.
cart dim [
/*Buy Able products*/ <= /*What to do?*/,
6 * 9 <= /*answ*/ + /*er*/,
/*able*/ <= always
];
To access or change values, put square square brackets behind the cart with the key.
/*Able*/ =: cart[always];
cart[/*What to do*/ + /*?*/] print;
BF functios
One of AbleScript's core functions is running BF code. Simple BF functio can be declarated using bff
keyword:
bff helloworld
{
++++++++++[>+++++++>++++++++++>+++>+<<<<
-]>++.>+.+++++++..+++.>++.<<++++++++++++
+++.>.+++.------.--------.>+.>.
}
Default tape size limit is 30 000 bytes, but that can be overriden using tape size parameter on declaration
bff helloworld (1200) { ... }
BF functios are called in same way as Able functios:
helloworld ();
You can specify input data as parametre.
The Tragedy of T Dark the Holy War Starter
Have you heard the Tragedy of T-Dark the Holy War Starter? He mixed up AbleLang and AbleScript and was executed for his sins.
For those cases, we are introducting you - dramatic pause - The T-Dark Block. Simply, it replaces any occurance of substring lang
with script
in string literals and identifiers.
T-Dark {
lang dim /*buy able products*/;
script print;
}
Finalisers
If you need to run some code at the end of the program, you can use the finally
block:
finally {
/*Goodbye!*/ print;
}
/*Hello!*/ print;
Output:
Hello!
Goodbye!
This is similar to defer
from other languages, but rather than executing at the end of the function, it executes at the end of the whole program.
Finally blocks are executed in the order they were defined.
Keywords
bff
- Declaration of BF functiobreak
- exit loopdim
- Declaration of variablefinally
- Finaliser blockfunctio
- Declaration of functioshopback
- jump to start of looploop
- infinite loopmelo
- Ban a variableprint
- Print preceding expression to stdoutrickroll
- Linkrlyeh
- Crash with random error codeT-Dark
- T-Dark blockunless
- unless condition