Quickstart
Just want to jump in? Well, plug your nose and in you go! All of these examples are complete and valid Brat programs.
Print something
Adds newline, too
p "hello world"
No newline
print "hello world"
Creating a new object
y = object.new
Subclassing:
y = object.new
x = y.new
Setting ‘fields’
person = new
person.name = "Bob"
p person.name
Defining functions
hello = { p "hello again, world" }
Functions return their last value. Parameters go in a list before a |
add = { lhs, rhs | rhs + lhs }
p add 1 2
You may also have functions with default arguments, variable arguments, or a mix of those and required arguments. Using an asterisk *
on the final formal parameter will gather up remaining arguments into an array.
any = { *args | p args }
any 1, 2, 3 # [1,2,3]
any # []
one_or_more = { first, *rest | p first, " - ", rest }
one_or_more 1, 2, 3 # 1-[2,3]
one_two_or_more = {first, second = "two", *rest | p first, second, rest }
one_two_or_more 1, 2, 3 #12[3]
one_two_or_more 1 #1two[3]
at_most_two = {first = "one", second = "two" | p first, second }
at_most_two # onetwo
at_most_two "hello" # hellotwo
Calling a function
Parentheses are optional, as are commas (sort of).
greet = { first, last | p "Greetings, ", first, " ", last }
greet "jane", "moe"
greet("john", "doe")
greet "someone" "else"
You can also use a hash-like notation to automatically pass in a hashtable of values. This hashtable will always be assigned to the last parameter in the function.
a = { x,y,z | p x, y, z["a"]}
a 1, "a": 3, 2
Multiple functions (or closures, or blocks) can be passed in like this:
a = { x,y,z | p "Ignoring everything..." }
a { "nothing" } { null } { 1 + 2 }
Getting a function
test = new
test.method = { x | p "You gave me: ", x }
x = new
x.method = test->method
x.method 123
another = { m | p "This is ", m }
x.another = ->another
x.another "me"
For ease of use, -> actually returns the ‘value’ in a variable, so you can use it with functions or objects without getting into trouble.
w = 1
x = { z | ->z}
y = { 2 }
p x w
p x y
p x ->y
Accessing current object
test = new
test.y = { my.z = { p "hi" } }
test.y
test.z
Strings
Go in single or double “quotes.”
a = "hello"
p a
You can do string interpolation with double quotes like this:
p "2 + 4 = #{2 + 4}"
Booleans
False and null are false, true and everything else are true.
false?, true?, and null? can each take 0 to 3 parameters. If a parameter is a function, it will be called with no arguments.
true.true?
true? true
This returns second parameter if first is true, otherwise returns false.
true? true, 1
This returns second parameter if first is true, otherwise returns second parameter.
true? true, 1, 0
a = null
false? { null? a }
{ p "a is not null" }
{ p "a is null" }
Numbers
Numbers are numbers. Most of the usual operators with the typical precedence are defined for them, too.
Arrays
Arrays are zero-based, dynamically resized lists which can contain anything.
a = array.new
a[0] = 3
p a[0]
b = [1, 2, 3, a, "b", { c | c }]
p b[5] "hello world"
Hashes
Hash tables, associative arrays, maps, dictionaries…whatever you want to call them, these are lists which can be indexed by an arbitrary value.
a = hash.new
a["a"] = 1
p a["a"]
b = ["a":1]
p b["a"]
c = { x | x}
b["c"] = ->c
p b["c"] 5
Binary Operators
You can define certain binary operators. These should always take one parameter. They can then be used as ‘infix’ notation. The ‘usual’ operators will have their typical precedence.
array.% = { i | my[i]}
a = [1,2,3,4]
p a % 3
p a.% 3
p a.%(3)
Regular Expressions
Regular expressions live in between /
and another /
.
a = /hel+o/
p a.match "helllllo"
Comments
Comments mark lines of code that will not be parsed or executed. They may be nested.
#this is a comment
#p "this will never print"
#*
use this for multiple line comments
*#
Comments may be nested.
Keywords
Brat does not have any keywords.
Semicolons
Semicolons are optional line enders and no one will cry if you don’t use them. They may if you do, though.