View on GitHub

Streemdox

🦬 Streem Documentation Project 🦬

Language

The Streem language consists of constants, variables, operators, and other elements.

Code comments

All code comments are prefixed with a hash.

./streem 01nil.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 02hobbies.strm

hobbies = ["yoga", "Tai Chi", "Qigong", "foreign languages", "Streem"]
hobbies | stdout

# Output:
# yoga
# Tai Chi
# Qigong
# foreign languages
# Streem

Assigning a variable

./streem 03assign.strm

Here’s how to assign value 3 to variable x.

x = 3

./streem 04assign.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 05operators.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 06multiplication.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 08hello-world.strm

Pipe what is traditionally said at the beginning of the programming journey to the standard output.

# 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 09hello-world.strm

It’s a hello world program that pipes multiple lines to the standard output. The ‘stderr’ file descriptor could have also been used in the example below.

x = ["HELLO,", "world"]
x | stdout

# Output:
# HELLO,
# world

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 10hello-world.strm

This particular hello program introduces a concept of procedures, i.e. functions without arguments.

# Output: HELLO
hello = () -> { "HELLO" }
s = hello()
print(s)

./streem 11hello-world.strm

More can be done when functions have arguments.

# 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 12add.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 13match.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