Basics

Everything you need to know to start writing Nebula code.

Variables

Declaration

# Constant (immutable) - use perm
perm MAX_SIZE = 1000
perm APP_NAME = "MyApp"
perm PI = 3.14159

# Variable (mutable)
count = 0
count = count + 1

# Multiple declarations
x = 10
y = 20
z = x + y

Naming Conventions

# Variables: snake_case
user_count = 0
is_active = on

# Constants: UPPER_SNAKE_CASE
perm MAX_RETRIES = 5
perm API_URL = "https://api.example.com"

# Functions: snake_case
fn calculate_total() do ... end
fn get_user_by_id(id) do ... end

Data Types

Numbers

Nebula handles integers and floats automatically:

# Integers
perm age = 25
perm year = 2024
perm negative = -100

# Floats
perm pi = 3.14159
perm price = 19.99
perm scientific = 1.5e10

# Operations
log(10 / 3)    # 3.333... (float division)
log(10 % 3)    # 1 (modulus)
log(2 ^ 10)    # 1024 (power)

Booleans

Use on and off instead of true/false:

perm is_active = on
perm is_deleted = off

if is_active do
    log("Active!")
end

# Logical operations
perm both = on and off     # off
perm either = on or off    # on
perm inverted = !on        # off

Strings

Text enclosed in double quotes:

perm greeting = "Hello, World!"
perm name = "Nebula"

# Concatenation
perm message = "Welcome to " + name
log(message)  # Welcome to Nebula

# String length
log(len("hello"))  # 5

# Accessing characters (0-indexed)
perm word = "hello"
log(word[0])  # h
log(word[4])  # o

Empty (Null)

Use empty for absence of value:

perm no_value = empty

if no_value == empty do
    log("Nothing here")
end

fn find(items, target) do
    each item in items do
        if item == target do
            give item
        end
    end
    give empty  # Not found
end

Type Checking

Use typeof() to inspect types:

log(typeof(42))        # "int"
log(typeof(3.14))      # "fl"
log(typeof("hello"))   # "wrd"
log(typeof(on))        # "bool"
log(typeof([1, 2]))    # "lst"
log(typeof({"a": 1}))  # "map"
log(typeof(empty))     # "nil"

Type Reference

Valuetypeof ResultDescription
42intInteger
3.14flFloat
"text"wrdString
on/offboolBoolean
[1,2,3]lstList
{"k":"v"}mapMap
(1, 2)tupTuple
emptynilNull
fn()=1fnFunction

Operators

Arithmetic

OperatorDescriptionExampleResult
+Addition5 + 38
-Subtraction5 - 32
*Multiplication5 * 315
/Division7 / 23.5
%Modulus7 % 31
^Power2 ^ 38
-Negation-5-5

Comparison

OperatorDescriptionExampleResult
==Equal5 == 5on
!=Not equal5 != 3on
<Less than3 < 5on
>Greater than5 > 3on
<=Less or equal5 <= 5on
>=Greater or equal5 >= 3on

Logical

OperatorDescriptionExampleResult
andLogical ANDon and offoff
orLogical ORon or offon
!Logical NOT!onoff

Bitwise

OperatorDescriptionExample
&AND5 & 31
|OR5 | 37
`^`XOR
~NOT~5
<<Left shift1 << 38
>>Right shift8 >> 22

Compound Assignment

x = 10
x += 5    # x = 15
x -= 3    # x = 12
x *= 2    # x = 24
x /= 4    # x = 6

Comments

# Single line comment

perm x = 10  # Inline comment

# Multi-line comments just use
# multiple single-line comments
# like this

Expressions vs Statements

Expressions produce values:

5 + 3           # 8
len("hello")    # 5
x > 10          # on or off

Statements perform actions:

perm x = 10     # Variable declaration
log("hello")    # Function call
if x > 5 do ... end  # Control flow

Scope

Variables are scoped to their block:

perm global_var = "I'm global"

fn my_function() do
    perm local_var = "I'm local"
    log(global_var)  # OK - can access global
    log(local_var)   # OK - can access local
end

log(global_var)  # OK
# log(local_var)  # ERROR - not in scope