Guide
Syntax
JS | Bizubee |
---|---|
a && b
|
a and b
|
a || b
|
a or b
|
!(a && b)
|
not a and b
|
!a || !b
|
!a or !b
|
a < b && b < c
|
a < b < c
|
a === b
|
a == b
|
a == b
|
no equivalent |
a == null
|
a?
|
(a == undefined)? undefined : a.b.c
|
a?.b.c
|
(func == undefined)? undefined : func()
|
func?()
|
Math.pow(a, b)
|
a ^ b
|
Math.floor(a / b)
|
a // b
|
return a
|
return a , |< a or a >|
|
yield a
|
yield a , << a or a >>
|
yield* a
|
yield * a , << * a or a * >>
|
this.a
|
@a or this.a
|
Line Breaks and Indentation
A line break in bizubee terminates a statement unless it ends in a strictly binary operator.
Bizubee also has optional indented blocks, such that
if 2 < 3 do
doSomething()
else
doSomethingElse()
Can also be written as
if 2 < 3 {
doSomething()
} else {
doSomethingElse()
}
Keep in mind that indentation is ignored within curly blocks.
Variables
All variables in Bizubee are block-scoped, as opposed to function scoped. Use var
to declare variables, and const
to declare constants.
if 2 < 6 do
var a = 7
const b = 6
# a and b are defined here
# a and b are undefined out here
For-loops
For-In
For-in loops are used to loop over a collection of values, and compile directly to for-of
loops in JavaScript. Any object that properly implements the Iterable interface can be iterated over with a for-in loop.
# Arrays are iterables!
const values = [3, 5, 6]
for value in values do
console.log("value is ${i}")
# prints:
# 3
# 5
# 6
For-On Loops
For-on loops iterate over an Async Iterable, and can only exist within async functions. There is currently no JS analog to the for-on loop, but there may be one soon. For now Bizubee has adopted the interface described in the proposal. The only difference is Symbol.asyncIterator
is replaced by symbols.asyncIterator
from the bizubee utils
library.
import {symbols} from bizubee utils
const myAsyncIterable = {
i : 0
values : []
next() -> {
@i += 1
return Promise.resolve({
done: (@i == @values.length)
value: @values[@i - 1]
})
}
[symbols.asyncIterable]: () -> {
return this
}
}
# function must be async
myAsyncFunction() -> ~ {
for value on myAsyncIterable do
console.log(value)
}
myAsyncFunction()
# asynchronously prints:
# 7
# 4
# 9
Functions
Bizubee has function expressions and function declarations. Similar to JS, function declarations are hoisted to the top of their scope.
# divide is already defined
console.log(divide(6, 2))
# declare function divide
divide(numerator, denominator) -> {
|< numerator / denominator
}
Whereas
# divide is not defined, so throws error
console.log(divide(6, 2))
const divide = (numerator, denominator) -> {
|< numerator / denominator
}
# divide is defined here
console.log(divide(6, 2))
Unlike JS, function declarations are constant, and cannot be reset.
Function Modifiers
In has generator functions, async functions, and async-generator functions. Each of the three function types requires a specific modifier.
Generator Functions
Generator functions are defined by a *
modifier after the function arrow. Generator functions in Bizubee are compile directly to their JS counterparts. See JS generator functions.
range(start, end, step = 1) -> * {
var i = start
while i < end do
yield i
i += step
}
for i in range(0, 3) do
console.log(i)
# prints:
# 0
# 1
# 2
Async Functions
Async functions are defined by adding a ~
after the function arrow. Async functions can contain await
expressions, which take a Promise/A+ argument. When an await
is encountered, function execution is paused until the promise is resolved. Once the promise is resolved, the await
expression evaluates to the resolution value, and function execution continues.
# ordinary function that returns a promise
httpGet(uri) -> {
const base = "Failed with status"
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = () => {
if xhr.readyState == 4 do
if xhr.status == 200 do
# everything went great
resolve(xhr.responseText)
else
# oops
reject(new Error("${base} ${xhr.status}"))
}
xhr.open('GET', uri, true)
xhr.send()
})
}
# async function that returns a promise
fetchJSON(uri) -> ~ {
const text = await httpGet(uri) # await promise
return JSON.parse(text)
}
fetchJSON(uri).then((json) => {
doSomethingWithJSON(json)
})
Async Generator Functions
Async generator functions are functions that implicitly return Async Generators which can be iterated over asynchronously with for-on loops. The ~*
or comet
operator is used as the modifier for async generator functions. Async generator functions can contain both await
expressions, and yield
statements.
An async generator function to iterate over a stream of JSON objects.
# ordinary function that returns a promise
httpGet(uri) -> {
const base = "Failed with status"
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = () => {
if xhr.readyState == 4 do
if xhr.status == 200 do
# everything went great
resolve(xhr.responseText)
else
# oops
reject(new Error("${base} ${xhr.status}"))
}
xhr.open('GET', uri, true)
xhr.send()
})
}
const urls = [
'http://some.domain/path/to/file1.json'
'http://some.domain/path/to/file2.json'
'http://some.domain/path/to/file42.json'
]
getJSONStream() -> ~* {
for url in urls do
const text = await httpGet(url)
yield JSON.parse(text)
}
useJSONStream() -> ~ {
for json on getJSONStream() do
doSomethingWithJSON(json)
}
# start running async function
useJSONStream()
Fat Arrow vs Thin Arrow
Fat arrow functions are defined using =>
instead of ->
. They are mostly analogous to fat-arrow functions in JavaScript, in that they do not have their own this
value. Instead, this
keeps the value of the parent scope in a fat-arrow function.
const myObj = {
val: 55
myMethod() -> {
myFatArrowFunction() => {
# this == myObj!
return this.val
}
return 3 + myFatArrowFunction()
}
}
# prints 58
console.log(myObj.myMethod())