Copper Reference Manual

This is a draft, it is not complete yet.

Lexical Conventions

Instructions

Instructions 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

Comments starts with two slashes.

// This is a comment

Identifiers

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

Identifiers are case sensitives.

A convention is to start type names with an upper case letter, other identifiers starting with a lower case letter.

Symbols

A symbol is an identifier starting with a single quote.

Keywords

List of reserved keywords:

and
attr
break
case
cond
const
do
else
elsif
end
enum
extend
function
if
import
method
not
or
ref
repeat
return
static
struct
stype
switch
var
while
yield

Builtin Constants

true
false
nil
Anything
Bool
Int8
Int16
Int32
Int64
Nil
Size
Unsigned8
Unsigned16
Unsigned32
Unsigned64

These constants are not keywords: the same name can be used for functions, methods or attributes as long as they take one or more argument.

Types

Some types can be used in place of another type:

  • A structure can inherit from another structure
  • An enumeration is an integer

Basic Types

NameDescription
Unsigned8unsigned 8 bit integer
Unsigned16unsigned 16 bit integer
Unsigned32unsigned 32 bit integer
Unsigned64unsigned 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
Nilthe type of the 'nil' constant

Pointers

* Type

Pointer to Type.

Arrays

[n] Type
[] Type

n is a positive integer. [] Type is an alias for [0] Type.

Examples:

[10] Int32      // an array of 10 integers
[10] [20] Int32 // a two dimension array of integer
*[] Char        // a pointer to an array of character 

Function Pointers

& (Type1, Type2, ...)
& (Type1, Type2, ...) -> (Return-Type1, Return-Type2, ...)

This type is a pointer, but the * is implicit.

Examples:

& (Int32, Int32) -> (Int32)
& (Int32)
& -> (Int32) // A function without argument

Named Types

A named type is an identifier that can be:

  • a basic type
  • the name of a structure
  • the name of an enumeration
  • the name of a sub-type
  • an alias to another type (const)

Expressions

Literals

Numbers

  • Decimals: (+|-)?[0-9]+
  • Hexadecimals: (+|-)?0x[0-9a-fA-F]+
  • ASCII: $c where c is any ASCII character from 33 to 126

Strings

  • "aaaa" // 8 or 16 bit character string

A string can includes special escaped characters:

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

Booleans

  • true
  • false

Initializers

{list-of-arguments}

The initializer is always evaluated depending on the expected type. If there is no expected type, the expression can be preceded with the 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.

Function and Methods References

ref function-name
ref function-name (list-of-types)
ref (type) method-name
ref (type) method-name (list-of-types)

function-name is the name of the function followed by the types of arguments between parenthesis. Do not put parenthesis if the function has no parameter.

Null Pointer

nil

nil is a pointer with value to 0 and its type is a special pointer type that matches with all pointer types, i.e. this value can be used anywhere a pointer value is expected.

Symbols

A symbol is an identifier starting with a quote representing a constant value.

'[a-zA-Z][a-zA-Z0-9]*

A symbol is always defined in a type and is resolved using the expected type. If no type is expected, it must be preceded by the correct one.

Type symbol

Tuples

A tuple is a list of values separated by commas

12, 34, "hello"

It can also includes expressions returning multiples values:

f(x), "hello"

If f(x) returns two values, this tuple has a cardinality of 3.

Operators

Arithmetic Operators

Unary:

+ -

Binary:

+ - * / %

Comparators

== <> < > <= >=

Bitwise Logical Operators

OperatorDescription
&and
|or
^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

Assignment

v1, v2, ..., vn = e1, e2, ..., em

assigns each value of the tuple e1, ..., em to each left value v1, v2, ..., vn. The cardinality of the right tuple must match the number of left values.

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

x, y = y, x

Combined Assignment and Operators

value OP= exp

is equivalent to:

value = value OP exp

Shortcuts for increment and decrement:

value ++
value --

The value must be a l-value. exp is an expression evaluating to a single value.

Conditional Operator

boolean-value cond e1 else e2

If the boolean value is true, the expression is evaluated to e1, e2 otherwise. e1 and e2 must have the same cardinality and must be compatible.

Only the expression corresponding to the boolean value is evaluated.

Dereference

e[]

e is an expression of type pointer

If the target type is not a simple type, the operator has no effect as the operator will return the effective address of the complex object.

Index Operator

e[n]
  • e is a pointer to an array
  • n is an integer

e[] is an alias for e[0]

Notes:

  • e can also be of another type if the operator is redefined.
  • the operator can take several arguments of any type when redefined:
    e[e1, e2, ...]
    

Function Call Operator

e call
e call (e1, e2, ...)
  • e is a pointer to a function
  • e1, e2, ... are the arguments

Type Conversion

e : Type

The type must be a simple type (an integer, a boolean or a pointer).

An integer cannot be directly converted to or from a pointer. It must be converted to or from a Size type first.

Type Accessor

@e

The type of the expression.

Function and Method Calls

Functions and methods without block:

f
f (arg1)
f (arg1, arg2, ...)
arg1 f
arg1 f (arg2, ...)

Functions and methods with block without parameters:

arg1 f (arg2, ...) do
  instr1
  instr2
  ...
end

Functions with block and parameters:

arg1 f (arg1, arg2, ...) do x1, x2, ...
  instr1
  instr2
  ...
end

Builtin Functions

Type size

Returns the size in bytes of the type.

Pointer target

Returns the target of a pointer type.

Array cell

Returns the cell type of an array type.

Type nil

Returns a null pointer of type *Type

x super

Returns x unchanged but the type is the parent type of x. It applies only to pointer to structures.

Statements

If

if cond1
  ...
elsif cond2
  ...
elsif ...
  ...
else
  ...
end

Where:

  • cond1, cond2 are boolean expressions.
  • elsif and else statements are optionals

While

while cond
  ...
end

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

Repeat

repeat
  ...
end

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

Switch

switch e
case c1
  ...
case c2
  ...
case ...
  ...
else
  ...
end

e is an integer or character expression. c1 and c2 are constant integers or characters. The else statement is optional.

Break

break

The break statement can interrupt a while or repeat loop.

Return

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

Returns zero, one or more values from a function.

Yield

yield
yield e1
yield e1, e2, ..., en

This statement evaluates the block passed to the function. The arguments of the yield are passed to the block as parameters. If there is more than one yield, all must have a compatible signature.

function loop(n)
    var i = 1
    while i <= n
        yield i
        i ++
    end

function main
    loop (10) do x
        printf("%d\n", j)
    end

Vargs_each

vargs_each do arg
    // Do something with arg
end

Enumerates all additional arguments of a function having variadic arguments.

e.g.:

function f (a, b, ...)
    vargs_each do arg
        print (arg)
    end
end

An expression such as:

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

will be generate an instance of f like this:

function f (a: Int32, b: Int32, arg1: Int16, arg2: String, arg3: Bool)
    print (arg1)
    print (arg2)
    print (arg3)
end

Declarations

Functions

function name (arg1: Type1, arg2: Type2, ...)
    ...
end

The type of each argument can be omitted. In such a case the function is generic: one function will be instanciated for each different type of argument.

// Fully generic
function name (arg1, arg2, ...)

// Mixed
function name (arg1, arg2: Type2, ...)

The return type of a function is automatically computed by the compiler.

Types of arguments cannot be structures or array, they must be pointers or basic types, i.e. values that can be stored in registers.

There is no end marker to functions, a functions ends when a new global definition starts.

Redefinition of Operators

Operators are just functions or methods with special name

NameOperation
_add+
_sub-
_mul*
_div/
_mod%
_shl<<
_shr>>
_eq==
_ne<>
_le<=
_lt<
_ge>=
_gt>
_and&
_xor^
_or|
_notnot
_assign_add+=
_assign_sub-=
_assign_mul*=
_assign_div/=
_assign_mod%=
_assign_shl<<=
_assign_shr>>=
_assign_and&=
_assign_or|=
_assign_xor^=
_assign_inc++
_assign_dec--
_at[]

Structures

struct Name [: Parent]

Creates a structure named Name.

A structure can include

  • Attributes
  • Methods
  • Statics
  • Functions
  • Constants
  • Enumerations
  • Variables
  • Imported methods
  • Imported statics

Inheritance

A structure can inherit from another structure, all attributes are inherited: it is equivalent to add them at the beginning. A pointer to a structure is also considered as a pointer to its parent structure.

Attributes

attr name: Type

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

aStruct name

Methods

method [+] name (...)
    instr1
    instr2
    instr3
end

A method is just a function defined inside a structure. There is a first implicit parameter that is a pointer to the structure, the value of the enum or the value of the extended type. The parameter is named self.

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.

Statics

static [+] name (...)
    instr1
    instr2
    instr3
end

A static is a method that is added to the meta-type instead of the type. The first implicit parameter is self and correspond to the type.

e.g.:

struct Point
    attr x : Integer
    attr y : Integer

    static new
        var pt = Point allocate
        pt x = 0
        pt y = 0
        return self
    end
end

function test
    var pt = Point new
end

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 static is instanciated for each derived type of self.

Enumerations

enum name [: Type]
    'item1 [= value1]
    'item2 [= value2]
    ...

    method name1 (...)
    ...
end

Defines an enumeration. If Type is not provided, the enumeration is a 32 bit signed integer.

Each item can have a value assigned to it. If the value is not specified, it gets the value of its predecessor plus one or zero for the first item.

Sub-types

stype name : Type
    'item1 [= value1]
    ...

    method name1 (...)
    ...
end

Defines a derived type of Type. The parent must be a simple type: either a pointer, an integer or a boolean.

e.g.:

stype String : *[]Unsigned8

    method isEmpty
        return self [0] = 0
    end
end

Aliases

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. e.g.

const screenWidth = Integer 640

Imports

To import public declarations of another module:

import "module-name"

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

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

To import an external function:

import function ["public-name"] name (Type1, Type2, ...)
import function ["public-name"] name (Type1, Type2, ...) -> (R1, R2, ...)

To import an external method:

import method ["public-name"] name (Type1, Type2, ...)
import method ["public-name"] name (Type1, Type2, ...) -> (R1, R2, ...)

To import an external static:

import static ["public-name"] name (Type1, Type2, ...)
import static ["public-name"] name (Type1, Type2, ...) -> (R1, R2, ...)

Extend

extend Type

It allows to add methods to any existing type.

e.g.:

extend Int32
    method high
        return self >> 16
    end
end

Global Variables

var name = value
var name : Type

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

Local Variables

var name = value
var name : Type

Defines a local variable in a function or a method with or without an initial value.