# 3A in two minutes

3A is a small, statically typed, expression-based language. A program is a list of `fn` declarations and must contain `fn main()`.

```3a
fn main() {
  print("Hello, 3A!")
}
```

## Rules

1. `fn main()` is required. It takes no parameters and has no return type.
2. One statement per line. No semicolons, no comments.
3. Bindings are immutable. `x = 1` binds `x` once per function. Rebinding or shadowing it is an error.
4. The last expression of a function body is its return value. There is no `return` keyword.
5. Every statement except the last must be a binding or a call that returns Unit. A value that is never used is an error.
6. `print` accepts only `Str`. Convert everything else with `to_str`.
7. `Int` and `Float` never mix. `1 + 2.5` is an error. Write `1.0 + 2.5`.

## Types

`Int` (unbounded), `Float`, `Str`, `Bool`, `Unit` (written `()`), and function types such as `(Int, Int) -> Int`.

## Functions

```3a
fn square(n: Int) -> Int {
  n * n
}

fn main() {
  print(to_str(square(12)))
}
```

A function without `-> T` returns Unit. Functions may be called before they are defined, and they are values:

```3a
fn twice(f: (Int) -> Int, n: Int) -> Int {
  f(f(n))
}

fn increment(n: Int) -> Int {
  n + 1
}

fn main() {
  step = increment
  print(to_str(twice(step, 40)))
}
```

## Expressions

- Literals: `42`, `3.14`, `"text"`, `true`, `false`
- Arithmetic on two values of the same number type: `+`, `-`, `*`, `/`, `%`, unary `-`, and parentheses
- `/` on `Int` truncates toward zero: `-7 / 2` is `-3`. Dividing by zero is a runtime error.
- Calls: `f(a, b)`

```3a
fn main() {
  x = 10
  y = 4
  mixed = -x * y + (x - y) / 2
  print(to_str(mixed))
  print(to_str(2.5 * 2.0))
  print(to_str(x * x * x * x * x * x * x * x * x * x * x * x * x * x * x * x * x * x * x * x * x))
}
```

## Control flow

`if` is an expression. With `else`, both branches must have the same type and the whole `if` has that type. Without `else`, the body must be Unit. The condition must be a `Bool`.

```3a
fn sign(n: Int) -> Str {
  if n > 0 {
    "positive"
  } else if n < 0 {
    "negative"
  } else {
    "zero"
  }
}

fn main() {
  for i in range(1, 16) {
    if i % 15 == 0 {
      print("FizzBuzz")
    } else if i % 3 == 0 {
      print("Fizz")
    } else if i % 5 == 0 {
      print("Buzz")
    } else {
      print(to_str(i))
    }
  }
  print(sign(-3))
}
```

`for x in list { ... }` runs the body once per element. The body must be Unit, and the loop variable is an immutable binding like any other. `range(start, stop)` is a `List[Int]` from `start` up to `stop - 1`. Recursion with `if` is the other way to loop:

```3a
fn sum_to(n: Int) -> Int {
  if n <= 0 {
    0
  } else {
    n + sum_to(n - 1)
  }
}

fn main() {
  print(to_str(sum_to(100)))
}
```

- Comparisons: `==` and `!=` on any two values of the same non-function type; `<`, `>`, `<=`, `>=` on `Int`, `Float`, or `Str`. They cannot be chained.
- `%` is the remainder of truncating division, so `-7 % 3` is `-1`.
- `and`, `or` short-circuit; `not` negates a `Bool`.
- Precedence, lowest first: `or`, `and`, `not`, comparisons, `+ -`, `* / %`.

## Builtins

- `print(s: Str)` prints one line.
- `to_str(value) -> Str` works on any value except a function.
- `range(start: Int, stop: Int) -> List[Int]`

## Not available yet

`match` and `type` are reserved. List literals, indexing, string concatenation, and the `Map`, `Option` (`T?`) and `Result` (`T!E`) types cannot be used in expressions yet, so the only list you can make is `range`.

## Errors

The checker stops the program before it runs and points at the exact span. Codes: `E01xx` names, `E02xx` operators, `E03xx` calls, `E04xx` functions and types, `E05xx` statements, `E06xx` control flow. Runtime: `R0001` integer division or remainder by zero, `R0002` non-finite `Float`, `R0003` more than 10,000 nested calls.
