Table of Content

Basic Syntax


Statements are separated by an end of line. The end of line is ignored when something more is expected, e.g. a line terminated with:

( , : = + - * ...


Comments start with two slashes.

// This is a comment


An identifier is a sequence of letters, digits and underscores starting with a letter or underscore.

Identifiers are case sensitives.

The convention is to start type names with an upper case letter and other identifiers with a lower case letter.

Reserved Keywords

List of reserved keywords:

and      defer     if        ref
attr     do        import    return 
break    else      loop      switch 
case     elsif     module    var  
class    end       not       while
const    extend    or
def      func      pass

These identifiers are not keywords but it is recommended to not redefine them:

true   self  sizeof  nil
false  Self  yield

Program Elements

At the top level, a Copper program is made of those elements:


var name = value
var name: Type
import var name: Type

Creates a global variable with or without an initial value. The initial value must be a constant.


const name = value
const name = Type

Defines an alias to a constant value or a type.

There is no expected type when evaluating the value, so it must be explicitely specified when using a literal:

const screenWidth = Int: 640


// Defines a function without parameter that returns nothing
func name

// Defines a function with parameters that returns nothing
func name(arg1: Type1, arg2: Type2)

// Defines a function with parameters that returns multiple values
func name(arg1: Type1, arg2: Type2): Type1, Type2

The type of each of parameters can be replaced by a *. In such a case the function is generic: one function will be instanciated for each type of parameters.

// Fully generic
func name(arg1: *, arg2: *)

// Mixed
func name(arg1: *, arg2: Type2)

// With a variadic parameter
func name(arg1: Type1, args: Type2...)
func name(arg1: Type1, args: *...)

Non-generic functions can be imported from other object files:

// Imports a function from another object file
import func name(Type1, Type2, ...)

// same but with return values
import func name(Type1, Type2, ...) -> (Type1, Type2, ...)

// Import a function with a name that differs from the symbol in the object file
import func "public-name" name(Type1, Type2, ...)


class Name

Defines a new class named Name. The class has no parent and represents a reference to a structure, it can have attributes.

class Name: Parent

Defines a new class named Name that is a subclass of Parent. The parent can be any simple type: a reference to a structure, a reference to an array or an integer type.

If the parent is a structure, it is possible to add new attributes.

A class can contain 3 specific elements:

A class can also contain any program elements except extend and import.

A special identifier, Self, is accessible inside the definition of the class, it is an alias to class itself. It avoids to repeat the name of the class everywhere, it can be especially useful with generic classes:

class HashTable(Key: *, Value: *, defaultCapacity: Int)

    def isEqual(other: HashTable(Key, Value, defaultCapacity)): Bool

    // becomes
    def isEqual(other: Self): Bool


module Name
    // content

A module can be used to define functions, variables, constants and classes into a separate namespace. A module can be seen as a class without instance, it can include all program elements but import and extend.

A module can be generic:

module Name(T: *, n: Int)


import "module-name"
import "module-name" Name

Imports public declarations from another module inside the same namespace or inside a separate namespace Name.

The name of the module is the path relative to the include path plus the filename without the extension (.co).

Circular imports are not permitted: modules cannot be inter-dependents.


extend Type

It adds methods to any existing type.


extend Int32
    def high: Int32
        return self >> 16

This is extensively used by the standard library to extend the built-in types, but it should not be used outside.


Directives are properties that will be assigned to a single element or all following elements in the lexical scope. Directives are defined between square brackets, separated by comma.

[private] // now all the following elements will be 'private'
var width: Int
var [public] height: Int // This variable will be public
var depth: Int // This one is still private

Some directives apply to the every elements such as the visibility (public, private) or the conditional compilation (when) while other apply only to specific elements.



At the program level, it tells which element will be visible when the file is imported by another file.

Inside a module or a class, it tells whether an element is accessible from another file (private elements are still accessible from the same file).

At the beginning of a file and at the beginning of a class or module, the visibility is always public.

Conditional compilation

when <condition>

It applies a condition to elements: if the argument evaluates to false, the elements are not compiled.

func [when debug] assert(x: Bool)

func [when not debug] assert(x: Bool)

Naming Conventions


By default, the public name of a function or variable is numbered to ensure unicity. To import or export definition with the C calling convention, use c.

Calling Conventions


Sets the calling conventions for functions.

Prevent Ignoring a Result


It applies to types, it forbids a return value to be ignored. This is usually used with an error type to prevent forgetting the processing of an error.

class [mustcheck] Err: Int

import func fopen(filename: String): Err

fopen("dummy") // error
var res = fopen("dummy") // ok

Entry Point


Marks a function as an entry point. A function that is not used is not compiled, this flag forces the compilation of a function.

Class Elements

The elements that can be found only inside a class.


attr name: Type

Defines an attribute in a class. Only structures can have attributes (a structure is a class without parent or a subclass of a structure).

An attribute is accessed with the same syntax as a method without parameter:

The attribute can be directly a structure or an array instead of a reference:

class Line
    attr color: Int[3]! // 3 integers embedded in the structure
    attr from: Point! // a point embedded in the structure
    attr to: Point!

In the above example, the attributes are not reference but the accessors of the attributes are references:

var line = ...
var c = line.color // c is a reference to the array of 3 integers (Int[3])
var p = line.from // p is a reference to the first point (Point)


def [*] name(...)

A method is just a function defined inside a class. There is a first implicit parameter, self, that is a reference to the object, the value of the enum or the value of the extended type. Methods as well as functions can take a block parameter. The syntax is the same as function, the only difference is the use of def in place of func.

The optional * means that self is a generic parameter: The type of self is the actual type instead of the type where the method is defined. It means that a new method is instanciated for each derived type of self.

Enum Values

id = value

An enum value is almost equivalent to a const, but the type must be of the class that contains it and a value can be automatically assigned if the class is an integer type.


Assignment Statements

dst1, dst2, ... = src1, src2

Assigns the expressions at the right of the equal sign to the destination expressions at the left. The number of values at the left and at the right must be equal. The following is correct as long as the function f returns two values:

v1, v2 = f(x)

The values at the left must be either a local variable, a global variable, an attribute or an array element.

All right expressions are evaluated before assignment, so a code like this to swap two variables is perfectly valid:

x, y = y, x

Assignment Operator Statements

dst += src
dst -= src
dst *= src
dst /= src
dst %= src
dst <<= src
dst >>= src
dst &= src
dst |= src
dst ^= src
dst op= src

is strictly equivalent to:

dst = dst op src

The operation can be invalid when the operator is overloaded and the return type is not compatible to the left argument.

Expression Statements

expr1, expr2, ...

Any expression can be used as a statement. This is usually used when invoking a function without value returned or then the return values are ignored.

A constant expression used as a statement is an error as it is likely a mistake in the program.

Local variables

var id: T

Defines a local variable that is uninitialized.

var id1, id2, ... = src1, src2, ...

Defines one or more variables with an initial value. The number of variables must match the number of values on the right.

If Statements

if cond1
elsif cond2
elsif ...

Where cond1 and cond2 are boolean expressions.

Switch Statements

switch e
case c1
case c2, c3
case ...

e is an integer expression. c1, c2 and c3 are constants. The else block is optional.

Contrary to many languages derived from C, a case block won't continue its execution on the next case block, there is no need of break statements.

While and Loop Statements

while cond

Repeat the block as long as the boolean expression cond evaluates to true.


A synonym for while true, and endless loop can that only be interrupted by a break or a return.

Return Statements

return e1
return e1, e2, ..., en

Returns zero, one or more values from a function.

Break Statements

break e1
break e1, e2, ..., en

The break statement interrupts a while or loop operation.

The break statement can also be used to interrupt a function when invoked from a block passed to a function.

Pass Statements

pass e1
pass e1, e2, ..., en

Inside a while or a loop, it takes no argument and go to the next iteration.

Inside a block passed as an argument of a function, it ends the execution of the block and 'pass' the arguments back to the function.

Defer Statements

defer aStatement


The statement will be executed when leaving the current block, either on normal exit, on return or on break.


Grouping Expression


Forces the precedence of operators.

Integer Literals


String Literals

"aaaa" // 8 or 16 bit character string 

A string can includes special escaped characters:

\aBell (7)
\bBackspace (8)
\fForm Feed (12)
\nLine Feed (10)
\rCariage Return (13)
\tTab (9)
\vVertical Tab (11)
\wWhitespace (32)
\'single quote
\"double quotes



Creates constant structures or arrays. The initializer is always evaluated depending on the expected type. If there is no expected type, prepend the expression with a type:

Type: [list-of-arguments]

The type must be a pointer either to a structure or an array. Arguments must match the type. Each argument must be a constant.

Typed Expressions

Type: expr

It sets the expected type when evaluating expr, this is useful when the expression is a literal or an initializer and it forces the type of the expression to the given type. The expression must be compatible with the type (an expression is compatible if its type is a sub-type or if the literal value fits with the type).

Simple Invocation

id(expr-list) do arg1, arg2

Without argument, id can refer to a constant, a local variable, a global variable, a function or a type.

With arguments, id can refer to a function or an instance of a generic type.

Contextual Invocation do arg1, arg2

If the expression is an object, id refers to an attribute or a method.

If the expression is a type, id refers to a static definition defined inside this type (a function, a variable, a class or a module).

Contextual Invocation with Implicit Context

.id(expr-list) do arg1, arg2

If the expected type for the expression is T, .id is equivalent to

Function and Attribute References

// Referencing a function accessible from the current scope
ref name
ref name(types)

// Referencing a method
ref (type) name
ref (type) name(types)

// Referencing a static function in a module or class
ref [type] methodname
ref [type] methodname(types)

name is the name of the function followed by the types of parameters between parenthesis. Do not put parenthesis if the function has no parameter. The type of parameters are required only if the function is generic.

ref (type) attrname

The offset of the attribute attrname of the class type. The expression has a Size type.

ref (expression) attrname

The address of an attribute of a given object.

Prefix Operators

- expr

Negates the value of a number.

not expr

On a boolean it inverts the value, on an integer it inverts all bits.

Infix Operators

Arithmetic Operators:

~Distance, this is used for the difference of two pointers


<Less than
>Greater than
<=Less or equal
>=Greater or equal

Bitwise Logical Operators:

^exclusive or
<<left shift
>>right shift
andand, eval 2nd expr if and only if 1st is true
oror, eval 2nd expr if and only if 1st is false

Indexed Access


Access the element of an array. If the elements of the array are not references, the value is a reference to the element.

If the index is omitted, it is equivalent to a 0 index.

The index can be any kind of integer.

This operator can be overloaded and can use any number or parameters (0, 1 or more).

Operator Precedence

Operator priority from lowest to highest:

and or
== <> < > <= >=
+ - ~ & | ^
* / % << >>
- not
. []

Operator Overloading

Operators are just regular methods.

a + b

is strictly equivalent to:


To overload an operator, you just have to know its secret name. Here is the list:

_add  +
_sub  -
_mul  *
_div  /
_mod  %
_shl  <<
_shr  >>
_eq   ==
_ne   <>
_le   <=
_lt   <
_ge   >=
_gt   >
_and  &
_xor  ^
_or   |
_not  not
_at   []

Built-in Definitions


Boolean constants:


The nil constant


It represents the null pointer and can be used as a reference to any structure or array.


Gives the size of a given type as a Size type.

To get the size of an array or a structure, don't forget to append a ! to the type or you'll get the size of the pointer.

class Color
    attr r: Uint8
    attr g: Uint8
    attr b: Uint8

sizeof(Color) // 8 == the size of a pointer on a 64 bit platform
sizeof(Color!) // 3 == the size of the structure


yield(e1, e2, ..., en)

This expression evaluates the block passed to the function. The arguments of the yield are passed to the block as parameters.

func rept(n: Int) do (Int)
    var i = Int: 1
    while i <= n
        i += 1

func main
    rept(10) do x
        println("\a", j)

The yield expression can return one or more values if the block returns one or more values using pass.

Type Methods


Returns the parent type. If the type has no parent, it will generate an error.


Returns the cell type of an array type.


Returns an initializer for the given structure Type1 that is automatically initialized using the methods and constants from Type2. For each attribute of the structure, the initializer will search for a definition with the same name in the given type: it must be either a constant or a method. If it is a function, the attribute will be initialized with a reference to this function. This automatic initializer is useful to generate virtual tables.

Conversion Methods


Returns the same expression but with its parent type.

Returns the same expression but with the given type. The new type must be a subtype of the expression.


Converts an expression to a new type. The following conversion are allowed:

Function Pointer Calls, e2, ...)

e is a pointer to a function and e1, e2, ... are the arguments to pass to the function.

Variadic Methods

The variadic parameter of a function supports 3 methods:


args.each do arg
    // Do something with arg

Enumerates all additional arguments of a variadic function. e.g.:

func f(a: *, b: *, c: *...)
    c.each do arg

An expression such as:

f(Int32:1, Int32:2, Int16:3, String:"hello", true)

will be generate an instance of f like this:

func f(a: Int32, b: Int32, arg1: Int16, arg2: String, arg3: Bool)


The number of arguments.



is expanded to the variadic arguments. It can be used to forward the arguments to another function.

func new(T: *, args: *): T
    var t = T.alloc
    return t


Built-in Types

All types known by the compiler:

Uint8Unsigned 8 bit integer
Uint16Unsigned 16 bit integer
Uint32Unsigned 32 bit integer
Uint64Unsigned 64 bit integer
Int8Signed 8 bit integer
Int16Signed 16 bit integer
Int32Signed 32 bit integer
Int64Signed 64 bit integer
SizeUnsigned integer with the size of a pointer
BoolBoolean type
AnythingSpecial type matching all types
PointerA pointer to Anything. This is the parent class to all pointers.
NilThe type of 'nil'



A pointer to an array of n Types. n is a positive constant integer.


Is an equivalent to Type[0].

Function Types

& (Type1, Type2, ...)
& (Type1, Type2, ...) -> (ReturnType1, ReturnType2, ...)
& [stdcall] (Type1, Type2, ...) -> (ReturnType1, ReturnType2, ...)

Defines a function type: the type of parameters, the type of returns and optionally a calling-convention.

Local Types


Structures, arrays and function types are implicitely pointer types. To use the type directly, e.g. to allocate on stack, embed in another structure or another array, the type must be followed by an exclamation mark.