Skip to the content.

Turbine Tutorials

Table of Contents

Hello, World!

The following example demonstrates a simple “Hello, World!” program in Turbine.

// Prints "Hello, World!" to the console
# main(args vec{string}) int
  print("Hello, World!")
  return 0

Indentation and Block Structure

Turbine uses indentation-based syntax to define code blocks, similar to Python. Code that belongs to the same block (such as inside functions, loops, or conditionals) must be indented consistently.

There are no {} or begin/end markers—indentation alone determines structure.

if x > 0
  print("Positive")
  print("Above zero")

Line Breaks Inside Expressions

Line breaks are ignored inside parentheses (), braces {}, and brackets []. This allows long expressions or collection literals to be split over multiple lines:

- nums vec{int} = vec{
  10,
  20,
  30,
  40
}

This makes it easy to write readable, multi-line data structures or function arguments.

Comments

Turbine supports two types of comments:

// This is a single-line comment

/* 
  This is a 
  multi-line comment 
*/

Variables and Data Types

Turbine uses explicit type declarations for variables. The syntax follows a straightforward pattern:

- x int = 42
- name string = "Turbine"
- numbers vec{int} = vec{1, 2, 3}
- config map{string, int} = map{"max": 100, "min": 1}

Basic Types

Collection Types

Variable Declaration

Variables are declared using the - symbol, followed by the variable name, type, and optional initialization.

- age int
- pi float = 3.14
- message string = "Hello"

If a variable is declared without an initializer, it is assigned a default value:

Type Inference

Turbine supports type inference, allowing you to omit the type when an initializer is provided:

- e = 2.71828  // Inferred as float
- greeting = "Hello"  // Inferred as string

Variable Scope

Turbine supports nested scopes using ---:

- x int = 10

---
  - y int = 5
  print(x + y)
---
  print(x)
  // y is not accessible here

Global Variables

Global variables are declared the same way as local variables but must be named using a single underscore on both sides, such as count or CONFIG. This naming convention is required to clearly distinguish globals from local variables.

- _count_ int = 0
- _CONFIG_ = map{"timeout": 30, "max": 100}

Global variables are accessible throughout the entire module and can be shared across imported modules.

Literals

Turbine allows you to assign values directly using literals. These include numbers, strings, booleans, and also collection values like vectors or maps.

Basic Type Literals

- i int = 42
- f float = 3.14
- s string = "hello"
- b bool = true

You can explicitly specify the type, but in most cases it’s simpler and more common to let Turbine infer the type from the literal:

- i = 42        // inferred as int
- name = "Bob"  // inferred as string
- ok = true     // inferred as bool

Collection Literals

To define a collection, write the type name followed by a pair of braces {} containing the elements.

- v vec{int} = vec{1, 2, 3}
- m = map{"a": 1, "b": 2}
- s = set{3, 1, 2}
- k = stack{1, 2, 3}
- q = queue{"x", "y", "z"}

Use commas to separate elements. For maps, each key is followed by a colon : and its value.

You can also spread the contents across multiple lines. Line breaks inside the braces are ignored, which helps keep code readable.

- m = map{
    "width": 100,
    "height": 200,
    "depth": 50
  }

Expressions and Arithmetic Operators

Turbine supports standard arithmetic and comparison operators. Expressions are evaluated using operator precedence similar to most C-like languages.

Arithmetic Operators

Operator Description Example
+ Addition a + b
- Subtraction a - b
* Multiplication a * b
/ Division a / b
% Remainder (modulo) a % b

Comparison Operators

Operator Description Example
== Equal to a == b
!= Not equal to a != b
< Less than a < b
<= Less than or equal a <= b
> Greater than a > b
>= Greater or equal a >= b

Logical Operators

Operator Description Example
&& Logical AND a and b
|| Logical OR a or b
! Logical NOT not a

Expressions can be combined and grouped with parentheses () as needed:

- x = (a + b) * 2
- result = !(x > 0 && y < 0)

Bitwise Operators

Turbine supports common bitwise operators for integer values:

Operator Description Example
& Bitwise AND a & b
| Bitwise OR a | b
^ Bitwise XOR a ^ b
~ Bitwise NOT ~a
<< Left shift a << 1
>> Right shift a >> 2

Bitwise operations are performed on the binary representation of integer operands.

- a int = 6       // binary: 110
- b int = 3       // binary: 011

print(a & b)      // 2 (010)
print(a | b)      // 7 (111)
print(a ^ b)      // 5 (101)
print(~a)         // -7 (two's complement)
print(a << 1)     // 12 (1100)
print(b >> 1)     // 1 (001)

Statements

Turbine provides various statements to define the flow and structure of your program. These include conditional branches, loops, and control flow modifiers.

if Statement

Executes code based on a condition:

if x > 0
  print("Positive")
elif x < 0
  print("Negative")
else
  print("Zero")

for Statement

The for statement has several syntaxes based on the collection type being iterated over.

Range-based loop

Iterates from a start to a stop value (stop value is not included). An optional step value can be included by adding , step after the range.

for i in 0..5
  print(i)  // prints 0 to 4

for i in 10..0, -2
  print(i)  // prints 10, 8, 6, 4, 2

Vector loop

You can iterate over a vec in two ways:

- v = vec{10, 20, 30}

for val in v
  print(val)  // 10, 20, 30

for i, val in v
  print(i, ":", val)  // 0 : 10, 1 : 20, 2 : 30

Map loop

You can iterate over entries of a map in the order they were added:

- config = map{"max": 100, "min": 1, "step": 5}

for key, val in config with i
  print(key, "=", val)  // max = 100, min = 1, step = 5

for val in config
  print(val)  // 100, 1, 5

Set loop

Loops over elements of a set in the order of the element’s values:

- myset = set{2, 1, 3}

for val in myset
  print(val)  // 1, 2, 3

Stack loop

Loops over elements of a stack in the order they were pushed, from bottom to top:

- mystack = stack{1, 2, 3}

for val in mystack
  print(val)  // 1, 2, 3

Queue loop

Loops over elements of a queue in the order they were enqueued, from front to back:

- myqueue = queue{"a", "b", "c"}

for val in myqueue
  print(val)  // a, b, c

while Statement

The while loop repeatedly executes a block of code as long as the specified condition remains true.

i = 0
while i < 5
  print(i)
  i = i + 1

The loop starts by checking the condition (i < 5). If it’s true, the loop body executes. The condition is checked again after each iteration, and the loop continues until the condition is false.

break Statement

The break statement exits from the nearest loop, causing the program to continue after the loop ends.

for i in 1..10
  if i == 5
    break  // Exits the loop when i equals 5
  print(i)

continue Statement

The continue statement skips the current iteration of the loop and moves to the next iteration.

for i in 1..10
  if i == 5
    continue  // Skips the iteration when i equals 5
  print(i)

The break statement terminates the loop entirely, while continue skips the current loop iteration but allows the loop to continue.

switch Statement

The switch statement evaluates an expression and selects the block of code to execute based on matching values. It does not fall through.

switch op
  case "+"
    print(a + b)
  case "-"
    print(a - b)
  default
    print("Unknown operator")

return Statement

The return statement ends the execution of a function and sends a value back to the caller.

# square(x int) int
  return x * x
# log_message(msg string)
  print("Log:", msg)

You may still write return explicitly if you want to exit early, but it’s not required at the end of a void function.

nop Statement

The nop statement does nothing. It serves as a placeholder when a statement is required syntactically but no action should be taken.

if debug
  nop  // intentionally do nothing

Functions

Function Definition

Functions in Turbine are declared using the # symbol followed by the function signature. Each function can have zero or more parameters, and it can specify a return type.

# add(a int, b int) int
  return a + b

You can omit the return type if the function doesn’t return a value:

# greet(name string)
  print("Hello, " + name)

Calling Functions

To call a function, use the function name followed by the arguments in parentheses:

- result int = add(3, 5)
greet("Turbine")

Structures

In Turbine, a structure (struct) is a composite data type that groups together related values. You define a struct using a section header with the struct name followed by struct.

Defining a Structure

A struct definition starts with a heading like ## Point struct, and its fields are declared below using the - syntax:

## Point struct
  - x int
  - y int

This defines a struct Point with two fields: x and y, both of type int.

Creating and Accessing Structures

To create and use struct values, write the struct name followed by field initializers in braces {}, using = to assign values.

# main()
  - p = Point{x = 10, y = 20}
  print(p.x)  // Outputs: 10
  print(p.y)  // Outputs: 20

Nested Structures

You can define structs that include other structs:

## Circle struct
  - center Point
  - radius float

# main()
  - c = Circle{center = Point{x = 5, y = 5}, radius = 10.0}
  print(c.center.x)  // Outputs: 5
  print(c.radius)    // Outputs: 10.0

This defines a Circle struct with a Point field named center and a float field named radius.

Passing Structs to Functions

Structs can be passed to functions like any other value. Here’s an example of a function that takes a Circle and returns its area:

# CircleArea(c Circle) float
  return 3.14 * c.radius * c.radius

# main()
  - c = Circle{center = Point{x = 0, y = 0}, radius = 10.0}
  - a = CircleArea(c)
  print(a)  // Outputs: 314.0

This function computes the area of the circle using the formula πr² (with π approximated as 3.14).

Enums

Enums in Turbine are user-defined types that represent a fixed set of named values. Each enum value can also store additional fields.

Defining an Enum

An enum definition starts with a heading like ## Month enum, followed by a header row that defines the field names. The header row must begin with a colon ::

## Month enum
  : symbol , name         , num
  - Jan    , "January"    , 1
  - Feb    , "February"   , 2
  - Mar    , "March"      , 3
  - Apr    , "April"      , 4
  - May    , "May"        , 5
  - Jun    , "June"       , 6
  - Jul    , "July"       , 7
  - Aug    , "August"     , 8
  - Sep    , "September"  , 9
  - Oct    , "October"    , 10
  - Nov    , "November"   , 11
  - Dec    , "December"   , 12

This defines an enum Month with 12 values, each having a symbol, a string name, and an integer num.

Using Enum Values

Enum values can be accessed using dot(.) notation and their fields can be read just like struct fields:

# main(args vec{string}) int
  - m = Month.Oct
  print(m)        // > Oct
  print(m.name)   // > October
  print(m.num)    // > 10
  return 0

You can also define enums with floating-point fields. Here’s an example for difficulty levels in a game:

## Difficulty enum
  : sym        , damage_coeff, time_coeff
  - EASY       , 0.5         , 1.5
  - NORMAL     , 1.0         , 1.0
  - HARD       , 1.5         , 0.8
  - NIGHTMARE  , 2.5         , 0.5

# main(args vec{string}) int
  - d = Difficulty.HARD
  print(d)              // > 2
  print(d.sym)          // > HARD
  print(d.damage_coeff) // > 1.5
  print(d.time_coeff)   // > 0.8
  return 0

This can be useful for adjusting game logic or configuration based on predefined modes.

Module Import

Turbine allows you to import built-in or user-defined modules using the > symbol.

Built-in Modules

To import a built-in module, you use the > symbol followed by the module name:

> math

For example, math provides standard mathematical functions like sqrt and constants like PI.

Once imported, you can access these functions and constants using the module name as a prefix:

math.sqrt(16)  // Returns 4.0
math._PI_      // Accesses the value of PI

User-defined Modules

If you have a user-defined module (a source file in the same directory), you can import it by specifying its name (without the file extension):

> my_module

You can then access the symbols defined within the module in a similar way:

my_module.some_function()
my_module._MY_CONSTANT_

Built-in Functions

Turbine provides several built-in functions that are useful for basic input/output operations and working with collections. Below are some examples.

I/O Functions

Turbine provides built-in functions for input and output operations. Below are some examples:

- name string
- age int = 25

// Printing to the console
print("Hello, World!")           // Prints "Hello, World!"
print("Name: ", name)             // Prints "Name: " followed by the value of 'name'
print("Age: ", age)               // Prints "Age: 25"

// Reading input from the user
name = input("Enter your name: ") // Prompts user to enter their name

// Formatting output
formatted = format("Hello, %s! You are %d years old.", name, age)
print(formatted)                  // Prints the formatted string

Example Output:

Hello, World!
Name: John
Age: 25
Hello, John! You are 25 years old.

Collection Functions

Turbine provides several built-in functions for working with collections such as vectors, maps, and stacks. Some examples are as follows:

- v = vec{10, 20, 30}
- m = map{"key1": 1, "key2": 2}
- s = stack{1, 2, 3}

// Vector functions
vecpush(v, 40)        // Adds 40 to the end of the vector
print(veclen(v))      // Prints the length of the vector (4)
print(v)              // Prints the contents of the vector

// Stack functions
stackpop(s)           // Pops the top element from the stack (3)
print(s)              // Prints the updated stack {1, 2}

// Map functions
print(mapkeys(m))     // Prints the keys of the map {key1, key2}

Example Output:

{10, 20, 30, 40}
4
{1, 2}
{key1, key2}

These are just a few examples of the functions available for collection manipulation. For more advanced operations, refer to the library reference.

FizzBuzz Example

To wrap up this tutorial, here is a complete FizzBuzz program written in Turbine. It demonstrates the basics of variable declaration, control flow, arithmetic, and output:

# main(args vec{string}) int
  for i in 1..100
    if i % 15 == 0
      print("FizzBuzz")
    elif i % 3 == 0
      print("Fizz")
    elif i % 5 == 0
      print("Buzz")
    else
      print(i)
  return 0

This simple example uses:

With this, you should now be ready to write real Turbine code. For more advanced functionality, refer to the Built-in Function Reference and the Built-in Module Reference.