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

1

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 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 functio
  • break - exit loop
  • dim - Declaration of variable
  • finally - Finaliser block
  • functio - Declaration of functios
  • hopback - jump to start of loop
  • loop - infinite loop
  • melo - Ban a variable
  • print - Print preceding expression to stdout
  • rickroll - Link
  • rlyeh - Crash with random error code
  • T-Dark - T-Dark block
  • unless - unless condition