Threadon / Basics

Basics

what a program looks like

The smallest program

Every program starts with a main function. That's where execution begins. Put this in a file called hello.th:

def main() -> Int32
    print("Hello, world!")
    return 0

Run it:

python3 -m compiler.main --run hello.th
Hello, world!

Here's what's going on:

Notice the def line ends with a colon, like Python. The body is indented. Indentation is what groups statements together, not curly braces.

How a file is laid out

A .th file is a list of top-level things. In any order:

That's it. Code that runs must live inside a function. The only statements that can appear at the top level of a file are function definitions, struct definitions, and imports.

Order matters. A function must be defined before it is called, and a struct before it is used. If you call something the compiler hasn't seen yet, you get Unknown function 'name'.

Put main at the bottom and the functions it calls above it:

def greet(name: String) -> NoneType
    print("Hello,")
    print(name)
    return

def main() -> Int32
    greet("John")
    return 0
Hello, John

Exceptions to the order rule: the standard library is auto-imported into every main program, and anything you import is available as soon as the import line is seen.

Comments

A # starts a comment. Everything after it on the same line is ignored. Comments can start at the beginning of a line or after code:

# this whole line is a comment
def main() -> Int32
    x: Int32 = 5  # a comment after code
    print(x)
    return 0
5

There is no multi-line comment. Start each line with # if you want a comment block.

Indentation

Indentation groups statements into blocks. The body of a function, the fields of a struct, and the branches of an if are all indented one level deeper than their header line.

Use spaces. Blank lines and comment-only lines are fine anywhere.

The compiler checks that lines that belong together sit at the same column. For example, an elif must be indented exactly as far as its if. Get it wrong and the compiler complains.

This won't compile:

if a:
    print(a)
  elif b:

because elif is not at the same column as if.

Literals

A literal is a value written directly in the code. There are four kinds.

Numbers

A whole number is an integer literal. It gets the type Int32.

x: Int32 = 42

A number with a decimal point is a float literal. It gets the type Float32.

pi: Float32 = 3.14

Scientific notation works, as long as the number has a decimal point:

big: Float32 = 1.5e2   # 150.0

Two things to know about float literals:

Both are listed under Limits.

Strings

Strings are written with double quotes:

name: String = "John"

Single quotes are not strings in Threadon. Only double quotes.

Three escape sequences work inside a string:

EscapeMeaning
\nnewline
\ttab
\"a literal double quote
def main() -> Int32
    print("line one\nline two")
    print("say \"hi\"")
    print("tab\there")
    return 0
line one line two say "hi" tab here

Bools

The keywords True and False are the two boolean literals.

ok: Bool = True
done: Bool = False

None

The keyword None is the value of type NoneTypeIt behaves just like None in python use it as return for functions that return nothing. More on that in Functions.

Names

Names of variables, functions, and structs can contain letters, digits, and underscores. They can't start with a digit.

These are reserved words. You can't use them as names:

def if elif else while for return and or not None class struct True False import from lazyimport lazyfrom as

for is reserved but not implemented yet. See Limits.

What errors look like

When the compiler rejects your code, it prints the error, the line number, the offending line, and a caret pointing at the problem:

Error: If condition must be Bool, got Int32 at line 3
      if x:
      ^

Errors happen at compile time. Threadon does not run your code to find these problems. It checks before anything executes.