= The programming language Elna
:toc:

== Introduction

Elna is a simple, imperative, low-level programming language.

It is intendet to accompany other languages in the areas, where a high-level
language doesn't fit well. It is also supposed to be an intermediate
representation for a such high-level hypothetical programming language.

== Expressions

The expression `@r.field` includes 3 expressions:

1. Variable expression `r`.
2. Field access `(r).field`.
3. Address taking `@(r.field)`.

The expression is evaluated in the above order. The postfix expressions
like field access have higher precedence than prefix operators.

=== Binary expressions

.Operator precedence
|===
|Precedence |Operator |Description

|1 |* / % |Multiplication, division and remainder.
|2 |+ - |Addition and subtraction.
|3 |<< >> |Left and right shifts.
|4 |= <> > < <= >=| Relational operators.
|5 |or xor &| Logical operators.
|===

=== Unary expressions

Unary expressions are expressions with a prefix operator followed by one
operand.

`@` (*at sign*) takes the address of its operand. The operand expression should be
addressable.

`-` (*minus*) negates a numeric value.

`~` (*tilde*) applied on a boolean acts as logical not. Applied on a numeric – as
bitwise not.

== Conditional statements

== Loop statements

== Type system

```
type = array-type | pointer-type | record-type | enumeration-type
    | procedure-type | identifier.
```

=== Primitive types

* Pointer
* Word
* Int
* Bool
* String
* Char

=== Pointer types

```
pointer-type = "^" type.
```

Example:
```
program;
var
  x: Int;
  y: ^Int;
begin
  y := @x;
  y^ := 0
end.
```

=== Static array

```
array-type = "[" expression "]" type.
```

Example:
```
program;
var
  array: [3]Int := [1, 2, 3];
begin
  array[1] := array[2]
end.
```

=== Procedure types

```
procedure-heading = "proc" identifier-definition
    "(" [field {"," field}] ")" return-declaration.
block = constant-part variable-part statement-part "end".
procedure-declaration = procedure-heading ";" (block | "extern").
return-declaration = ["->" "!" | "->" type].
procedure-type = "proc" "(" [types] ")" return-declaration.
```

Example:
```
program;
var
  a: proc(Int) -> Int;

proc f(x: Int) -> Int;
end;

begin
  a := f;
  a(0)
end.
```

=== Records

```
field = identifier ":" type.
record-type = "record" ["(" identifier ")"] [field {";" field}] "end".
```

Example:
```
program;
type
  T = record
    x: Int
  end;
  U = record(T)
    y: Int;
    z: Int
  end;

var
  u: U;
begin
  u := U(0, 1, 2);
  u.x := 3
end.
```

=== Enumerations

```
enumeration-type = "(" identifier {"," identifier} ")".
```

Example:
```
program;
type
  E = (one, two, three);
var
  e: E;
begin
  e := E.one
end.
```

=== Type operations

=== Cast

```
cast = "cast" "(" expression ":" type ")".
```

The type of an object can be reinterpreted with a cast expression:
`cast(object: Type)`.

=== Traits

```
trait-identifier = "#" identifier.
trait = trait-identifier "(" [types] ")".
```

Traits allow to query some information about the types, like their size or
field offset or alignment. Calling a trait looks like a procedure call but
traits names start with a `#` and their arguments are type expressions and
not value expressions.

Supported compiler traits:

- `#size(T)` queries type size.
- `#align(T)` queries type alignment.
- `#offset(T, F)` queries the offset of the field `F` in the record `T`.

== Appendix

=== Syntax

```
letter = "A" | "B" | … | "Z" | "a" | "b" | … | "z" | "_".
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9".
character = ? a printable character ?.
hex-digit = digit | "A" | "B" | … | "F" | "a" | "b" | … | "f".
binary-digit = "0" | "1".

identifier = letter {letter | digit}.
identifier-definition = identifier ["*"].
trait-identifier = "#" identifier.

integer-literal = digit {digit}.
word-literal = integer-literal "u"
    | "0" ("X" | "x") hex-digit {hex-digit}
    | "0" ("B" | "b") binary-digit {binary-digit}.
real-literal = digit {digit} "." digit {digit}.
string-literal = """ {character} """.
character-literal = "'" {character} "'".

literal = integer-literal | word-literal | real-literal
    | string-literal | character-literal
    | "true" | "false" | "nil".

trait = trait-identifier "(" [types] ")".
cast = "cast" "(" expression ":" type ")".
procedure-call = designator "(" [expressions] ")".

relation-operator = "=" | "<>" | "<" | ">" | "<=" | ">=".
multiplication-operator = "*" | "/" | "%".
addition-operator = "+" | "-".
shift-operator = "<<" | ">>".
unary-operator = "@" | "~" | "-".

selector = "[" expression "]" | "." identifier | "^".
case = expressions ":" optional-statements.

designator = reference selector | identifier.
reference = literal | designator | trait | cast | procedure-call
    | "(" expression ")".
factor = unary-operator factor | reference.
term = factor {multiplication-operator factor}.
simple-expression = term {addition-operator term}.
comparand = simple-expression {shift-operator simple-expression}.
relation = comparand {relation-operator comparand}.
operand = relation {"&" relation}.
expression = operand {("or" | "xor") operand}.

expressions = expression {"," expression}.
identifier-definitions = identifier-definition {"," identifier-definition}.
types = type {"," type}.
required-statements = statement {";" statement}.
optional-statements = [required-statements].

return-declaration = ["->" "!" | "->" type].

field = identifier ":" type.
array-type = "[" expression "]" type.
pointer-type = "^" type.
record-type = "record" ["(" identifier ")"] [field {";" field}] "end".
enumeration-type = "(" identifier {"," identifier} ")".
procedure-type = "proc" "(" [types] ")" return-declaration.
type = array-type | pointer-type | record-type | enumeration-type
    | procedure-type | identifier.

assignment = designator ":=" expression.
if-statement = "if" expression "then" optional-statements
    {"elsif" expression "then" optional-statements}
    ["else" optional-statements] "end".
while-statement = "while" expression "do" optional-statements
    {"elsif" expression "do" optional-statements} "end".
defer-statement = "defer" optional-statements "end".
case-statement = "case" expression "of" case {"|" case}
    ["else" optional-statements] "end".
label-declaration = "." identifier.
goto-statement = "goto" identifier.
statement = assignment | procedure-call | defer-statement
    | label-declaration | goto-statement |
    | while-statement | if-statement | case-statement.
statement-part = ["begin" required-statements | "return" expression
    | "begin" required-statements ";" "return" expression].

constant-declaration = identifier-definition ":=" expression.
constant-part = ["const" {constant-declaration ";"}].
variable-declaration = identifier-definitions ":" type
    [":=" (expression | "extern")].
variable-part = ["var" {variable-declaration ";"}].
type_declaration = identifier-definition "=" type.
type-part ["type" {type-declaration ";"}].
import-declaration = identifier {"." identifier}.
import-part = ["import" {import_declarations ";"}].

procedure-heading = "proc" identifier-definition
    "(" [field {"," field}] ")" return-declaration.
block = constant-part variable-part statement-part "end".
procedure-declaration = procedure-heading ";" (block | "extern").

declaration-sequence = import-part
    constant-part type-part variable-part {procedure-declaration ";"}.
program = "program" ";" declaration-sequence statement-part "end" "."
    | "module" ";" declaration-sequence "end" "."
```
