1 Introduction
This manual describes the programming language Honey Badger. It is named Honey Badger as a reference to a youtube video popular on the internet in the early 2010’s. It is a dynamically-scoped, dynamically-scoped, language with a reference implementation provided in OCaml.
Honey Badger is a small language that could be implemented in an interpreted language quite straight-forwardly. It’s features were chosen without regard to practicality with the main goal of being different from other languages that the author has implemented and providing an avenue to prove his knowledge of OCaml by using it for the reference implementation.
A Honey Badger program is a single expression. This expression can contain loops, functions, branching, arrays, dictionaries, and is Turing-Complete.
The default behavior of a program is to evaluate it and if evaluation terminates print what it evaluates to. This manual is divided into informal and formal components. For a short, informal overview, the first part (through Section 9) suffices. The formal description begins with Section 10.
2 Getting Started
If you want to get started coding in Honey Badger you should download the
reference implementation which is
documented here and at it’s github page. After resolving dependencies
and making it you can run programs with HB path/to/file.hnb. Example programs
can be found in the “tests/input” directory, with tictactoe.hnb being
particularly informative.
3 Expressions
Expressions represent the entirety of Honey Badger syntax.
3.1 Constants
The simplest expressions are constants. Boolean constants are true and
false. Integer constants are made of the decimal digits without any other
char. String constants are characters enclosed in double
quotes, i.e. “Hello World!”
3.2 Identifiers
The names of variables are expressions. Resolution is done by checking the
current scope and if not present checking increasingly higher scopes.
Evaluating an identifiers which does not have a binding in any higher scope
will raise a ValueException.
3.3 Assignment
An assignment either has the form id = expr, id[expr] = expr, or
id[String] = expr. The first form assigns to regular variables, the second
to elements of an array, and the third to fields of a dictionary.
3.4 Method calls
Method calls take the form of <expr>(<expr>,...,<expr>). Let’s number these
e0(e1,…en) To evaluate this expression, we evaluate e0, throw an error if
it’s not a method or if it’s number of arguments does not equal n.
The args are evaluated left-to-right, from e1 to en. Finally, the values from
e1 to en are bound to the corresponding parameters names in a new scope and the
function itself is evaluated.
3.5 Conditionals
A conditional has the form
if <expr> then <expr> (else <expr>)
To evaluate conditionals, the predicate is evaluated first.
If the predicate is true, then the then branch is evaluated. If the predicate
is false, then the else branch is evaluated. The value of the conditional is
the value of the evaluated branch. If the else branch is not provided it is
defined as else Unit.
3.6 Loops
A loop has the form
while <expr> <block>
The guard is evaluated before each iteration of the loop.
If the guard is false, the loop terminates and returns Unit.
If it’s true, the body of the loop is evaluated and the process repeats.
If it’s anything else, a TypeException is raised.
There is also a for loop syntax of the form
for(e1; e2; e3) e4
This is semantic sugar for {e1; while e2 {e4; e3}}.
3.7 Blocks
A block has the form
{ <expr>; ...; <expr> }
The expressions are evaluated from first to last. Empty blocks are prohibited. Blocks evaluate to the last expression. Semi-colons in Honey Badger are used as seperators in the list of expressions not as terminators, unlike in C.
3.8 Input-Output
Honey Badger has the following built-in methods for performing simple input and output operations: print(x) : Unit readline() : String print casts its argument to a string, prints the result, and returns Unit. The method readline, waits for the user to type in a string followed by ‘\n’, and then returns the string without the newline.
3.9 Methods
A method definition has the form
fun <id, ... ,<id> : <expr>.
There may be zero or more parameters. The identifiers used in the parameter
list must be distinct.
3.10 Casts
Casts have the form Type(expr). Casts from floats to ints are done by truncation.
true cast to a number is equal to 1, false cast to a number is equal to 0.
Non-zero numbers cast to Bool are true, zero is false. Casting an expr e to Str
produces a string that that would evaluate to e. Non-empty arrays and records
cast to Bool are true, empty ones are false. All other casts generate a TypeException.
3.11 Arithmetic and Comparison Operations
Honey Badger has eight binary operators: +, -, *, /, >=, >, <, <=. Used as
expr op expr
To evaluate such an expression first expr1 is evaluated and then expr2. The
result of the operation is the result of the expression.
The static types of the two sub-expressions must be Int. The static type of the
expression is Int. Cool has only integer division.
Cool has three comparison operations: <, <=, =. For < and <= the rules are
exactly the same as for the binary arithmetic operations, except that the result
is a Bool. The comparison is a special case. If either
3.12 Array and Dictionary Literals
Array literals are in the form of [e1,...en]. Dictionary literals are in the
form of {"f1" : e1, ... "fn" : en} and prohibit duplicate fields. In both
cases, evaluation proceeds left-to-right.
3.13 Lookups
The notation
expr '[' expr ']' as in e[i]
whether on the left or right hand side on an assignment refers to the ith member of
the array e. The array is evaluated before the index. Array indexes start at 0.
If an array index evaluates to a float it is cast to an integer by truncation, if it
evaluates to a non-number a TypeException is raised. Arrays may be of freely mixed
types. Out-of-bounds errors on arrays generate OutOfBoundsException.
The notation expr '[' String ']' as in dict[“Hi”] refers to the field “Hi” within the
dictionary given by an expression. Evaluating a field not present in a dictionary will
raise a KeyException.
3.14 Throwing Exceptions
Exceptions can be thrown by language built-ins as described above or thrown
manually with the forms Except(expr) and Except(string, expr). The first
type throws a RuntimeException with expr cast to a Str as its message. The
second form throws an Exception of type specified by the given string with its
message as the expr evaluated and cast to a Str.
If an Exception is thrown without being caught, then its message shall be
print out by the interpreter.
3.15 Catching Exceptions
Exceptions can be caught by try-catch blocks. These have the form
try block (catch name : e)+. try’s without catch blocks are forbidden.
try’s where multiple catch blocks are provided for the same exception are also
forbidden.
4 Lexical Structure
The lexical units of Honey Badger are numbers, types, operators, strings, keywords, the various curlies anc brackets, and white space.
4.1 Numbers, Identifiers, and Special Notation
Integers are non-empty strings of digits 0-9. Floats are non-empty strings of digits 0-9 containing a single ‘.’ character. Identifiers are strings (other than keywords) starting with a lower case letter and consisting of letters, digits, and the underscore character. All types are currently keywords, but they all start with upper case letters for clarity.
4.2 Strings
Strings are enclosed in double quotes “…” and are all literal strings.
4.3 Comments
Honey Badger has one form of comment. Any string starting with “//” and ending with either a newline or EOF is a comment and ignored.
4.4 Keywords
The keywords of Honey Badger are: true, false, if, then, else, for, try, catch, fun, print, len, readline, Int, Bool, String, Float, Record, Top, Except, and Arr. Keywords are case sensitive.
4.5 White Space
White space consists of any sequence of the characters: ‘ ‘, ‘\n’, and ‘\t’.
5 Semi-formal Syntax
program = expr
expr = ID | ID "[" expr "]" | ID "[" string "]" | ID "=" expr |
ID "[" expr "]" "=" expr | ID "[" string "]" "=" expr |
expr bin_op expr | un_op expr | "fun" (ID,*) "=" expr |
expr "(" (expr,*) ")" | "if" expr "then" expr "else" expr |
"if" expr "then" expr | "while" expr block | "[" (expr,)* "]" |
"{" (string ":" expr)* "}" | type "(" expr ")" | Except "(" expr ")" |
Except "(" charseq "," expr ")" | int | float | bool | "(" expr ")" |
"for" "(" expr ";" expr ";" expr ")" expr | "print" "(" expr ")" |
"readline" "(" ")" | "try" block ("catch" charseq ":" expr)+
block = "{" (expr ";")+ ")"
bool = "true" | "false"
int = ['0'-'9']+
float = ['0'-'9']* '.' ['0'-'9']+
string = '"' charseq '"'
type = "Int" | "Bool" | "String" | "Float"
ID = ['a'-'z']['a'-'z' '0'-'9' 'A'-'Z' '_']*
charseq = [^'"' ' ' '\n' '\t']*
bin_op = "+"' | "-" | "/" | "*" | "<" | "<=" | ">" | ">="
un_op = "~" | "not" | "-"