Learn Jeebox Syntax

Most people approach Jeebox from a "coder's viewpoint", or a "knowledge representation" viewpoint. I feel there is a natural and good reason for these two separate viewpoints.

For this reason I'll explain "Jeebox for code" on this page, and "Jeebox for the real world" on the DRS page. But really, there is only one Jeebox.


Contexts



Jeebox has two contexts. Argument context, and list context.

{ // argument context } ( // list context )

This affects parsing. The flow of things is...

{ // argument context temporal_statement thing operator thing return a + b } ( // list context thing operator thing a + b )

Whats a "temporal statement"? Thats my name for commands like "return", "if", "do", "class", etc, that come at the start of a line.



Argument Context Syntax



Argument context, can contain temporal statements. This differs from lists and arrays, which can't.

{ return x // a temporal statement. }

You can easily construct wierd syntax, like:

{ return return // return a variable, named "return". }

but it's best to avoid doing things like that.

The goal of the rules is to allow the kind of syntax that has become natural to modern computer programmers.

if (a > b) { a = b + 1 return a + c }

This basically parses, as you would expect.



Lists



Brackets, and lists, have the same "parse context". The only difference is that a list contains one or more "end-of-line".

( a or b b or c c or b ) // List

(a or b) // Bracket

Lists are very expressive.

(a, b, c)

Above is a list with 3 items.

(a,)

Above is a list with 1 item. Just like in Python, actually.

(a:b)

Above is a list where we have a string index "a" and a value of a "thing" named "b".

(a, b:c, d:e, f, g)

Above, the index/value pairs don't have to be used on every item, you are free to mix and match as you like.

Despite this "free-form", this syntax can unambiguously express any list, or normal bracket.



Arrays



Arrays have the same meaning as lists, they just use slightly different syntax.

[a, b, c]

Unlike some languages that force you to use "object indexes" (Javascript/Python)... Jeebox allows you to choose:

(string_index: value) [object_index: value]

Apart from the index being strings for lists, and objects for arrays, the meaning of lists and arrays is the same.

Object indexes let you use any expression for the index of an array:

[a+b: value1, obj.func(x): value2, c: value3] // a list with 3 items. // index 1 is a+b // index 2 is the result of obj.func(x) // index 3 is just object "c"

Arrays don't need any "special rule" to express a list of 1 item, but lists do.

(a,) // list of 1 item [a] // array of 1 item



Precedence



Jeebox basically does away with precedence, with one exception described in "temporal operators".

x = 2 * 3 + 1 // x = 8 x = 1 + 2 * 3 // x = 7

The reason for this, is that Jeebox's operators are extensible. You can add new operators as you like.

x = 1 plus 2 times 3 x = 1 mod 2 curl 3

With no predefined operators, precedence is impossible. So we just abandon it entirely. This actually makes programs more predictable, because now you don't need to find some list of precedence rules, to figure out what comes first, you simply look at the order in which the operators appear.

x = a - b - c - d x = (a - (b - (c - d))) // same order as above!



Temporal operators



"Temporal Operators" have a higher precedence than non-temporal operators. They begin with # and can be any word...

( Fred lay down #until the~sky was clear Fred ran #while ~he could )

"#until" and "#while" are temporal operators, and come first. This makes the above example, parse as you'd expect. While temporal operators are aimed for "knowledge representation" rather than code, actually you can use temporal operators to describe the code itself.

this~window plays music #until the~user presses the~cancel~key



Normal Operators



You can use any name for any operator, you like.

x = y dot z // "dot product" is used in 3D Maths. x = y ∓ z // operators can be utf-8

Inbuilt comparison operators.

=  >=  <=  >  <  !=

Inbuilt arithmetic operators.

∗  -  +  /  >>  <<  ^

There are 4 unitary operators. They come before their parameter, and "bind" to their parameter more tightly than other operators. You can't add unitary operators.

!y, -y, &y, $y

All arithmetic operators and named operators (but not unitary or comparison operators) can be used in "+=" form, just like in C.

x += 3 x mod= 4



Units and numbers



Numbers can be in a few forms:

-1, 0, 0.5, 10.5 // nothing unusual here 9_000_000_000 // 9 billion. Underscore visually breaks up long numbers, without changing the meaning.

Units are extensible and quite fun:

10USD, 808rgb, -3i, 0FEFF_x, 010101b

Units start with a number and end with a letter. They are "read backwards" to find the first digit from 0-9 or "_". That is why 0FEFF_x will parse as a number of value "0FEFF" in the "x" unit. (Basically just an easy way to write hex in Jeebox).

Units can be utf-8.

10.95£, 10.95¥, 10.95$, 10.95元, 10.95€, 10.95ƒ



Strings



Jeebox strings are pretty powerful and flexible... mostly because I was fed up with other languages having bad string support. You can embed Jeebox code in strings.

x = "Hello {user}! We have {count} pieces of mail waiting for you." // strings can contain variables!

x = "The volume of {obj.name} is {x * y * z}m^3." // you can use any expression...

Letters can be escaped, using "escape codes" or "character references":

x = "\{\}" // escape codes let you express curly brackets.
y = "\n\t\r" // newline, tab, carriage-return

a = "(&#x134;&#xEB;\C3\AA\C6\81o&#9447;)"
b = "(ĴëêƁoⓧ)" // lines "a", and "b", have the same string value.

Right there... we have a few ways of representing Unicode characters (codepoints). "&#x134;" is Hexadecimal. "&#9447;" is decimal.

Unlike in Javascript / Java / C# / etc, in Jeebox one character reference will express any codepoint, even ones above 0xFFFF.

Jeebox also lets you write raw bytes... by using "\". To enter Unicode using raw bytes, it must be valid UTF-8 (like \C3\AA\C6\81). But you might want to write something else than Unicode... so you don't have to write valid UTF-8.

Jeebox accepts Unicode directly... like "(ĴëêƁoⓧ)" so you don't need character references or anything special to store Unicode.



More conventional syntax



#!/usr/bin/speedycog // you can use the "shebang" to make shell scripts be executable. x = Obj.func // functions on objects, can be called using "." x = func(name:"Fred", age:42) // parameters can be passed by name x = func("Fred", 42) // or without a name x = -1 // numbers can be negative. x = arr[x] // arrays can be accessed x = arr[x][y] // nested arrays too x = arr[a, b] // but you can pass multiple indexes. Much like in Python. y = x++ // just like in C y = x-- // just like in C y = x+=1 // just like in C x = "abc" // you have strings x = 'x' // and characters (like in C). if \ (A.LongFuncName and \ B.LongFuncName(WithAFew,LongParamNames) or \ C.AnotherLongName) { DoStuff( ) // you can visually break up long statements using "\" }



Declarations and types



Jeebox uses |bars| to declare things.

class example { |int| a b c |string| x y z } function example2 (|int| a b c, |string| x y z) { |int| d = a + b + c }

The type can be omitted. This allows for type inferencing.

|| x = 5.5

Typecasting uses ||, but after the object's name.

x = y|int|



Temporal statements



Temporal statements are easily the most flexible part of Jeebox!

Temporal statements, are words that start on a line, within "Argument context".

return x // temporal_statement, because its a word at the start of a line exit // temporal_statement (count) // not a temporal statement! A bracket around a thing named "count".

However, there are two exceptions:

a = 1 // a "relationship", because we have a syntactic operator after the word. exit(-1) // a function, because there is no space between the bracket and the name.

example temporal statements:

return x + 1 while (true) { output "hi" // like "print" but with a line at the end } for (a = 1 to 10) { output a } for_each (curr_file:file_list) { output curr_file.name } select (A, B, C) from T where (D > 0)

Temporal statements, use a special rule to make code parse more naturally... Any word after an argument, is a nested temporal statement. Meaning you can do this:

if (name = "admin") { // "if" is a temporal statement print "Hello admin!" } elseif (name = "") { // "elseif" is also a temporal statement! print "Where's your name?" }

Finally, using a colon ":", it is possible to put temporal statements, into places that a "thing" (number/object/etc) would normally go. This can be used to get a temporal statement as a thing.

x = :function example {print "example"}



Summary



Jeebox syntax is powerfully expressive and fun-to-use. Jeebox was designed so that all it's features work together in harmony.



Next: Read about the Jeebox AST.