IBX is a easily-parsable data format meant for emulating language syntax (especially Domain Specific Language).
IBX consists of mostly binary trees constructed with infix syntax, thus the name infix binary expression.
IBX is inspired by LISP S-Expression and APL.
The following characters has special meaning in IBX, and thus cannot be used as part of an identifier.
Name | Visual |
---|---|
Parenthesis | ( ) |
Square brackets | [ ] |
Curly brackets | { } |
Single quote | ' |
Double quote | " |
Backtick | ` |
Type | Example |
---|---|
Identifier* | foo + -> |
String Literal | "Hello World!" |
Numeric Literal | 123.783 |
Parenthesized expression | (1 + 2 - 3) |
Note: Identifier are either alphanumeric+underscore+dollar characters OR composed of non-whitespace, non-alphanumeric and non-reserved characters.
The main feature of IBX are binary trees that are left-associative[1].
Trees constructed based on the following rules:
Tokens | Parsed Binary Tree |
---|---|
a b |
a b |
a b c |
a b c |
a b c d |
(a b c) d |
a b c d e |
(a b c) d e |
a b c d e f |
((a b c) d e) f |
Tokens | Parsed Tree |
---|---|
1 ! |
1 ! |
1 + 1 |
1 + 1 |
1 + 1 ! |
(1 + 1) ! |
1 + 2 - 3 |
(1 + 2) - 3 |
1 + 2 - 3 ! |
((1 + 2) - 3) ! |
1 + 2 - 3 * 4 |
((1 + 2) - 3) * 4 |
Array is composed of a list of tokens enclosed within a pair of square brackets.
For example, the following array contains 3 elements.
["Hello world" 123 (1 + 3)]
Object is composed of a binary tree enclosed within a pair
of curly brackets. IBX object is similar to JSON object,
however, the number of keys may be one less than the number of
values, where the first value has an implicit key 0
.
This particular difference allows IBX to better encode DSL
than JSON as it is less verbose.
Example (when tokens count is odd):
IBX | JSON-5 |
---|---|
{"hello"} |
{0: "hello"} |
{1 and 2} |
{0: 1, and: 2} |
{1 < 2 < 3} |
{0: 1, "<": 2, "<": 3} |
Example (when tokens count is even):
IBX | JSON-5 |
---|---|
{name "Bartholomew"} |
{name: "Bartholomew"} |
{name "Ginger" size [1 2 3]} |
{name: "Ginger", size: [1,2,3]} |
{$and: [{likes: {$gt: 1}}, {age: {$ne: 1}}]}
likes $gt 1 $and (age $ne 1)
<a class="link" href="https://hello.com">
<span>Hello world</span>
<span>Yo</span>
</a>
{a class "link" href "https://hello.com" _ [
{span _ ["Hello world"]}
{span _ ["yo"]}
]}
[1, 2, 3]
.filter(x => x % 2 === 0)
.map(x => x + 1)
.reduce((a, b) => a + b, 0)
[1 2 3]
filter (x => (x % 2 === 0))
map (x => (x + 1))
reduce [+ 0]
0 3 */2 3-4 FRI
[0 3 (* / 2) (3 - 4) FRI]
query GetKrabbyPatty($size: Size!) {
getKrabbyPatty(size: $size) {
id
sauce
cookedBy {
name
}
}
}
query (GetKrabbyPatty {$size (!Size)}) {
(getKrabbyPatty {size $size}) {
id,
sauce,
cookedBy {
name,
}
}
}
select
id, species as name
from
fruit
where
kind = 'tropical' and color = 'red'
order by created_on;
{
select
[id (species as name)]
from
fruit
where
(kind = 'tropical' and (color = 'red'))
orderBy
created_on
}
- Initially, IBX uses right-associativity instead of
left-associativity due to influence from APL. However, after browsing through
operators tables in various mainstream languages like
C++ and JS, I found that most of the operators are
left-associative, where right-associative operators are
mostly assignment operators like
=
or+=
. Thus I felt that left-associativity should appear more natural to most users, myself included.