Syntax
======

The syntax is intended to be as familiar as possible for programmers used to C like languages, along with some now pretty standard quality of life improvements such as nested comments and optional semicolons.

The top level of the file is a function, similarly to Swift.

Local variables
---------------

Variables are declared with the same syntax as classic C like languages, a type followed by a name.

All variables have to be initialized, but some types, such as integers, define a default initialization value.

    bool b = false      // Booleans have to be initialized explicitely.
    uint(32) someInt    // Integers have a default initialization value of 0.

There is local type inference (like C++'s auto or C#'s var, with a few additional possibilities), but no hindley-milner inference.

    var something = someFunc()
    $T somethingElse = someFunc()   // Same as above but also captures the type in the $T template variable.
    list[$T] = someFuncReturningSomeList()

A local variable can be declared inside of an expression, like in c++, in which case its visibility and life duration will extend only to the statement it is part of.

Functions
---------

Function types are declared with a type followed by a list of parameters, like in C. They can optionally be followed by [contract specifications](contracts.md).

    void()
    uint(32)( uint(32) a, uint(32) b) requires [ a>b ] ensures [ @>0 ]

Functions are declared like in C. Here is an example with contract specifications:

    uint(32) lomarf( uint(32) a, uint(32) b )
        requires [ a>b ]
        ensures [ @>0 ]
    {
        return a - b
    }

Note that functions can contain nested functions. After all, the top level of the file is also a function.

Functions can return multiple values. See [tuples](tuples.md) for more informations. Note: this only works at compilation time at the moment, as no runtime representation of the tuple type have been implemented yet.

    uint(32), bool func()
    {
        return 123, false
    }

When a function is encountered, it is tokenized but not fully parsed and compiled until it is called or passed as a function pointer. This allows functions to be able to call each other without requiring to be forward declared. However, the top level code of the file can only call a function that have been declared beforehand.

It also means that if a function is never called, it will never be compiled so any error that it contains will not be diagnosed. This will be remedied in the future by keeping track of functions that have never been compiled and compiling them at the end of the compilation process.

A particularity is that functions can define parameters that are constant values:

    void what( "lomarf" )
    {
        ...
    }

This function can be called only if the compilation time string lomarf is passed:

    what( "lomarf" ) // ok
    what( "laffo" ) // error: doesn't match the string expected by the function.

While this may seem strange and useless, it becomes meaningful when combined with [overloading](overloading.md) to define a specialization or a partial specialization of a template function, especially considering that [types](types.md) themselves are compilation time values.

Operators
---------

The same set of operators as C++ have been implemented, with the exception of the increment and decrement operators (++ and --). Their precedence are the same with the exception of the comma. In goose, the comma is used to construct tuples and have a higher precedence than the = operator.

In practice, almost everything in goose is an expression, including types themselves (because types are values of "type" type). More information can be found on the [types](types.md) page.

More information on the implementation of the parser and how it can be extended can be found in [extensibility](extensibility.md).

Control statements
------------------

Currently, only if, while, break, continue and return are implemented. They work like in C++. Syntactically, they are more permissive as the parentheses around while/if conditions are optional.

Note that it is possible to omit either, or both the parentheses and the braces around single statement blocks, as long as there is no ambiguousness:

    if a == b lomarf()

Works just as well as

    if( a == b ) { lomarf() }

Note that there is no implicit conversion of anything into a bool. Checking if something is not equal to zero requires to explicitely write "if something != 0".
