Language
The Streem language consists of constants, variables, operators, and other elements.
Code comments
All code comments are prefixed with a hash.
./streem nil.strm
# minimal program that can be called NIL
Types
Value | Type |
---|---|
“HELLO, world” | string |
true, false | boolean |
42 | integer |
4.2 | float |
[1,2,3] | array |
x -> x | function |
map, flatmap etc | built-in function |
stdin, stdout etc | file descriptor |
x | y | x can be a stream |
Standard output with streams
It’s possible to pipe an array into standard output without calling a function. Just use the bar operator. This construct will be used in the sections covering the language features. Calling ‘print()’ or ‘puts()’ can be preferred elsewhere. The elements are placed vertically on a screen, i.e., they are separated with a new line character.
./streem hobbies.strm
hobbies = ["yoga", "Tai Chi", "Qigong", "foreign languages", "Streem"]
hobbies | stdout
# Output:
# yoga
# Tai Chi
# Qigong
# foreign languages
# Streem
Assigning a variable
./streem assign-42.strm
Here’s how to assign the 42 value to variable x.
x = 42
./streem assign-hello.strm
Over here, we assign “HELLO, world” to a variable s.
s = "HELLO, world"
TODO: array, concept of stream, print using stream
Arithmetic expressions
Use the basic arithmetic operators to perform computations.
Operator | What is? |
---|---|
+ | sum |
- | difference |
* | multiplication |
/ | division (float) |
% | remainder |
./streem operators.strm
x_1 = 2 + 3 # 5
x_2 = x_1 * 4 # 20
x_3 = x_2 / 4 # 5
x_4 = x_3 - 3 # 2
x_5 = x_4 % 2 # 2
[x_1, x_2, x_3, x_4, x_5] | stdout
# Output:
# 5
# 20
# 5
# 2
# 0
Logical expressions
Logical operators are not implemented. Source code that uses them won’t parse.
There’s an ‘||’ operator for logical “or”, and ‘&&’ operator for logical “and”.
Parentheses
You can enclose expressions in brackets to formulate more complex expressions.
./streem multiplication.strm
# Output: 20
x = (2 + 3) * 4
[x] | stdout
if statements
If statements are done using the keywords ‘if’ and ‘else’. Use “else if” to add more cases
In the following example, “Two” is assigned to the variable s and printed out.
./streem one-or-two.strm
# Output: Two
x = 2
if (x == 1) {
s = "One"
} else if (x == 2) {
s = "Two"
} else {
s = "Unknown"
}
[s] | stdout
Concatenate strings
Strings can be concatenated with the plus operator. Here’s an example that can be part of a traditional Hello World program.
./streem pipe-hello-world.strm
# Output: HELLO, world
name = "world"
s = "HELLO, " + name
[s] | stdout
The s parameter’s value is now “HELLO, world”.
Array
Arrays are one of the fundamental data types in Streem. They are declared as [x_1, x_2, …, x_3].
Standard I/O
The ‘stdin’, ‘stdout’ and ‘stderr’ are file descriptors used for the standard I/O operations.
Stream
Arrays are fundamental data types. Their items are enclosed within square brackets. They can be used with a streaming operator |.
./streem pipe-hello-world-multiline.strm
x = ["HELLO,", "world"]
x | stdout
# Output:
# HELLO,
# world
The ‘stderr’ file descriptor could have also been used in this example.
Functions
Functions are defined within the curly brackets in a lambda-expression manner. Arguments are used, and the last expression is the return value.
./streem hello-world-function.strm
# Output: HELLO
hello = () -> { "HELLO" }
s = hello()
print(s)
./streem hello-world-function-with-arguments.strm
# Output: HELLO, world
hello = { name ->
"HELLO, " + name
}
s = hello("world")
print(s)
Functions with multiple parameters
To pass multiple arguments to a function, a matching number of parameters needs to be declared and surrounded by brackets. More than 2 parameters are allowable.
./streem add.strm
add = (x, y) -> x + y
addz = (x, y, z) -> {
xy = add(x, y)
add(xy, z)
}
a = 123456789
b = 987654321
puts(add(a, b))
puts(addz(a, b, 1))
# Output:
# 1111111110
# 1111111111
Pattern matching
There’s a pattern matching for functions. It’s a functionality similar to a switch statement in non-prototypical languages. The “case” expression has to return a value depending on whether the two passed arguments match. The underscore can be used for default cases. Variables and string literals can be passed as arguments.
./streem match.strm
Tests whether an input animal is a cat.
# Input:
# elephant
# cat
# dog
# kitty
matches = {
case "kitty", "cat" -> true # match
case "cat", "kitty" -> true # match
case "doggie", "dog" -> true # match
case "dog", "doggie" -> true # match
case x, x -> true # identical
case _, _ -> false # no match
}
stdin | map { x -> matches("cat", x) } | stdout
# Output:
# false
# true
# false
# true
Namespaces
Namespaces are structures that consist of variables and functions that can be imported and used. An unimported namespace can’t be used. They can be used for greater clarity and to group data.
./strm highlander.strm
# Output:
# There can be only one
# There can be only one.
namespace highlander {
tagline = "There can be only one"
taglineDot = () -> { tagline + "." }
}
import highlander
print(tagline)
print(taglineDot())
Classes
Classes are identical to namespaces, although one could expect to instantiate objects with them. You can import them and use their read-only content.
./strm rpg.strm
# Output: 19
class player {
hp = 19
}
import player
[hp] | stdout