Brackit

From Esolang
Jump to navigation Jump to search

Brackit is a predominately stack-based esoteric programming language with characteristics of object oriented design. Brackit was created by Blake Lockley in 2015, designed mainly for code golfing challenges. The language is still currently in development but alpha versions for testing can be downloaded here.

Concept

The language draws inspirations heavily from the similar stack-based language ><> and various popular object-oriented programming languages such as Java, Swift and Objective-C. The name "Brackit" comes from the way objects are defined in the language - by declaring the name followed by opening and closing brackets with the objects code in between.

Brackit has the general attributes of similar stack based programming languages but the defining feature of the language is its ability for the user to create objects containing its own stack, variables and methods (functions relating to the object) assigned to a user-defined single-character name. Each Brackit program written will automatically contain a "main" object where program wide variables and functions can be declared.

Stack

Each object in Brackit including the "main" object has its own stack, as the Interpreter executes the program values will be "pushed" onto the stack, certain operators (such as math symbols) will "pop" the top two elements of the stack and perform the instructed operation and push the resulting value. Brackit also contains a range of stack based instructions that can be used to manipulate the stack, push and pop stack related values. The stack is composed solely of numbers (specifically floating-point numbers / floats) characters pushed onto the stack will be pushed as their corresponding ASCII code.

Pop: The top value of the stack is removed and the instruction called will be executed on the value.

Push: The value created by the instruction will be put as the top value of the stack.


Pushing the value of 6 then 8 onto the stack. (Note: This pushes the individual numbers 8 and 6 as opposed to pushing 68, although, this can be done with parsing)

68               Stack Contents: [ 6 , 8 ]


Pushing hexadecimal values onto the stack. This pushes the hexadecimal value a (10) and f (15).

af               Stack Contents: [ 10 , 15 ]


Pushing the values 2 and 4 onto the stack then performing addition.

24+              Stack Contents: [ 6 ]


Pushing 1, 9 and 7 onto the stack and using the l instruction to push the length of the stack onto the stack.

197 l             Stack Contents: [ 1 , 9 ,  7 ,  3  ]

Note: Spaces can be included in your code and will do nothing, this is useful when creating code but obviously should be removed for code golf


Variables

Variables can be declared by a single character name, the initial value assigned to the variable will be popped from the stack, if the stack of the current object is empty, 0 will be automatically assigned to the variable. Once a variable is defined the value stored can be accessed by using the variables name, this results in the variables value being pushed onto the stack (note this does not change the value of the variable).

Declaring a variable z with the initial value of 9. (9 is pushed onto the stack then the value is popped and assigned to z)

9z               Stack Contents: [ ] Variables: [ z : 9 ]


Declaring a variable y with the initial value of 0 since the stack is empty.

y                Stack Contents: [ ] Variables: [ y : 0 ]

Each object contains its own set of variables subsequently the same variable name can be used in different objects, if a variable is declared with the same name in the main object and also the current object, using the variables name will push the value from the variable of the current object.

Declaring variable x with the initial value 6, then calling x pushing its values onto the stack

6x x             Stack Contents: [ 6 ] Variables: [ x : 6 ]

A secondary effect of calling a variable is that the variable will become the current objects "open variable". This allows for the variable to be reassigned to a new value by "closing" the variable with the _ (close) instruction. Closing a variable pops the top value from the stack and reassigns the popped value to the open variable. This feature allows for variables to be easily modified.

Closing the variable w with a new value that is 2 more than its previous value. (The variable w was previously declared with the initial value 8)

w2+_
^^^^
||||_ Close w variable by popping the value of 10 and assigning it to w    Stack: [  ]        Variables: [ w : 10 ] 
|||
|||__ Pop x and y from the stack and push x + y                            Stack: [ 10 ]      Variables: [ w : 8 ]
||
||___ Push 2 onto the stack                                                Stack: [ 8 , 2 ]   Variables: [ w : 8 ]
|
|____ Calling w will push its value of 8 to the stack                      Stack: [ 8 ]       Variables: [ w : 8 ]

Note: It is important to use new characters that are not already defined as instructions when naming variables (and also functions or objects). Declaring variables with the same name as instructions will cause unexpected behaviours (and probably a lot of head aches). A good tip is to use z,y,x and continue through the alphabet backwards, remember a-f are for pushing hexadecimal values 10-15.

Functions

Functions can be created to allow repeatable code to be written only once and executed multiples times with a single character. Functions are defined by declaring the name following opening and closing braces with the functions body between the pair of braces. As you most likely know functions are supposed to take arguments, the equivalent in Brackit can be considered pushing argument values (or variables) to the stack before calling the argument.

Declaring a function z that duplicates the top value on the stack of 7

z{2*}
7 z              Stack Contents: [ 14 ]

Declaring a function y that requires an argument, this function is designed to increase the top value of the stack by half the argument. 5 is on the stack while 4 is the argument

y{2/+}
5 4y             Stack Contents: [ 7 ]

Objects

Objects contain their own stack, variables and methods (functions that relate to the object). This is useful for creating specialised areas of code for larger code golf challenges. Creating an object is done by declaring the name of the object followed by opening and closing brackets with the objects contents inside. Providing instructions for objects works exactly the same as they do outside of an object (remember the normal body of the program is all inside the "main" object!). It is convention and highly recommended to name objects with capital letters although not necessary. Calling the object is done by simply including the declared name in the code - this makes the object the "current" object meaning all following instructions are executed onto this object other than the main one, this allows for arguments to be passed to various methods of the objects. The execution of instructions will return to the main object once a function is called on the object or the terminator instruction . is reached. In many cases values belonging to an object will need to be retrieved into main object, the "return" instruction ^ will pop the top of the stack of the current object and push it to the stack of the main object.

Declaring an object A, this object is a simple counter with a variable x to hold the current count and a method z to increment the count

A[ x z{z1+_} ]                  Object A: Variables: [ x : 0 ]
Az Az Az                        Object A: Variables: [ x : 3 ]


Declaring an object B, to model a real bike it has:

  • Variable: w - Wheels: how many wheels on the bike
  • Variable: s - Speed: the current speed of the bike
  • Method: z - Accelerate: This takes one argument and increases the speed by that amount
  • Method: y - Speed per Wheels: This divides the speed of bike by the number of wheels and returns the result to the main stack (not that this is how physics works lol)
B[ 2w s z{s+_}  y{sw/^}]        Object B: Variables: [ w : 2 , s : 0 ]
B7z                             Object B: Variables: [ w : 2 , s : 7 ]
By                              Main Object: Stack: [ 3.5 ]

Loops

In all programming languages recursions is very important, Brackit has two types of loops; "for" loops and "while" loops, both of which you would probably recognise from most languages. The amount of time each loops executes differs between the two. The for loops which is represented by a ! and a . with the executable code inside will pop the top value from the stack before the loop begins and subsequently repeat the code within the loop that amount of times. The while loop on the other hand represented by ~ and . with the executable code inside will execute its containing code and then pop the stack at the end of each loop, if the popped value is non-zero the loop will be repeated otherwise the loop will exit and execution will continue as normal. Subsequently this mean thats the code in the while loop will always be executed at least once (note this may be altered to pop the top value at the beginning of each loop to rectify this).

For loop repeating 5 times

5!'a'o.
Output: aaaaa

While loop repeating until the length l of the stack is 0

"olleh" ~ol.
Output: hello

Input/Output

In Brackit input can be provided from the command line and easily pushed onto the stack. Similarly output in two different forms (number or ASCII value) can be popped from the stack and printed to the command line. These instructions are very similar to those of ><> while even using the same characters, Brackit differs by the fact that during input multiple values may be pushed on the stack at once and multi didgit numbers can be provided, pushing their explicit numerical value as opposed to the ASCII value of its characters.

Instructing your program to take input can be done by including the i instruction, this will pause the execution of your program until the user provides input and presses enter. Brackit will determine if the input can be pushed as number or as a set of charcaters.

Providing the input "cat" to your program

i
Input: cat
Stack: [ 99 , 97 , 115 ]

Providing the input -178.66 to your program

i
Input: -178.66
Stack: [ -178.66 ]

Providing a string and a number as input will result in all the values being pushed as characters

i
Input: dog 7
Stack: [ 101 , 111 , 103 , 32 , 55 ]

Note: the value 32 correlates to the space character and the value 55 correlates to the ASCII character for 7

To output character values the "output" instruction o can be used, to output values as the numbers they are the "number" instruction can be used. Both of the instructions cause the top value to be popped and printed to the command line in the instructed format.

Pushing 6 to the stack and then printing it using the n instruction

6 n
Output: 6


Pushing the characters "cat" on the stack and printing it using o instruction

"tac" ooo
Output: cat

Note: the characters for "cat" were pushed onto the stack in reverse this is necessary as the o instruction will pop the value from the top of the stack first, the stack may also be reversed with the r instruction.

Pushing the character "a" to the stack twice and outputting it has a character and a number

"aa" on
Output: a97

Referring to an ASCII Table is extremely useful when programming in Brackit.

Parsing

Parsing can be preformed on numbers and strings to push their values onto the stack. When the " instruction is met the code will read all subsequent code as characters and push their ascii value to the stack until the next " is met, the exact same behaviour is present from the ' instruction.

Pushing "abc" onto the stack. Notice how they show up in the stack as their ASCII code

"abc"                  Stack: [ 97 , 98 , 99 ]
'efg'                  Stack: [ 100 , 101 , 102 ]

Parsing Numbers is a feature of Brackit that allows for obscure numbers to be created easily without tedious manipulation. Numbers can be passed easily by creating two opening and closing parenthesises and including the desired number inside, this number can have multiple digits, be negative and also contain a decimal point.

Push -56.087 onto the stack

(-56.087)              Stack: [ -56.087 ]

Instructions

Examples

Interpreters

Brackit.swift The official interpreter of the Brackit language. Latest version is downloadable here. The language is still in development thus changes will most likely be made. A Mac OS is needed, In the terminal simply type swift Brackit.swift file to run the file in the same directory as the interpreter. Brackit programs do not require any extension, .txt and .bkit can be used if desired.

Brackit.py Official interpreter for Python coming soon.