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.

Keywords

List of reserved keywords:

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

Builtin Constants

true
false
nil
Anything
Nil
Char8
Char16
Bool
Int8
Int16
Int32
Int64
Unsigned8
Unsigned16
Unsigned32
Unsigned64
Enum

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
Char88 bit character type
Char1616 bit character type
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
  • an alias to another type (const)

Expressions

Literals

Numbers

  • Decimals: (+|-)?[0-9]+
  • Hexadecimals: (+|-)?0x[0-9a-fA-F]+

A literal number is 32 bit signed. A cast can be used to get a different type:

123:Unsigned8   // unsigned byte
12345:Int16     // signed short
0x5f:Unsigned8  // unsigned byte

Strings

  • "aaaa" // 16 bit char string
  • 'aaaa' // 8 bit char 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

If two literal strings are adjacents, they can be concatened: "abc" "def" is same as "abcdef". It can be useful for long string, since you can join two lines with the '\' character:

"abc" \
"def"

Characters

  • $c for regular characters
  • \c for escape characters, one of:
    CharacterDescription
    \aBell (7)
    \bBackspace (8)
    \fForm Feed (12)
    \nLine Feed (10)
    \rCariage Return (13)
    \tTab (9)
    \vVertical Tab (11)
    \wWhitespace (32)
  • \nn for numeric characters

The type of a literal character is Char16.

Booleans

  • true
  • false

Initializers

Type [list-of-arguments]

Type is a either an array or a structure. Arguments must match the type. Each argument must be a constant.

Function References

ref function-name
ref function-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 use anywhere a pointer value is expected.

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

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

When there is no argument:

call (e)
e call

Type Conversion

e : Type

Function and Method Calls

Functions without block:

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

arg1 f              // alternative syntax
arg1 f (arg2, ...)  // alternative syntax

Functions with block without parameters:

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

Functions with block and parameters:

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

Builtin Functions

size (Type)

Returns the size in bytes of the type.

next (Enumeration)

Returns the last value + 1 of an enumeration

target (Pointer)

Returns the target of a pointer type.

nil (Type)

Returns a null pointer of type *Type

super (x)

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

Uninitialized Data

{Type}
  • If the type is a simple type (integer, boolean, ...), it just represents an uninitialized value.
  • If the type is a complex type (structure or array), space is allocated on stack or on heap and the value is the address of the allocated space.

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

Each_extra

each_extra do arg
    // Do something with arg
end

Enumerates all additional arguments of a function having variadic arguments.

e.g.:

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

An expression such as:

f (1, 2, 3, "hello", true)

will be generate an instance of f like this:

function f (a: Int32, b: Int32, arg1: Int32, arg2: *[]Char16, arg3: bool)
    print (arg1)
    print (arg2)
    print (arg3)

Declarations

Functions

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

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

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 function:

name (aStruct)
aStruct name

Methods

method name (...)
    instr1
    instr2
    instr3

A method is just a function defined inside a structure, an enumeration or an extension with two differences:

  • There is a first implicit argument that is a pointer to the structure, the value of the enum or the value of the extended type. The argument is named self.
  • The name of a method can override a global function. When the compiler find an expression f (arg1, ...) or arg1 f (...), it first search a definition in the dictionary of the type of the first argument.

Statics

static name = value

A static is just a constant defined in a structure that is accessed like an attribute.

e.g.:

struct Test

    attr x : Int32
    static y = 1
    
    method succ
        return self x + self y

Enumerations

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

    method name1 (...)
    ...

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.

Aliases

const name = value
const name = Type

Defines an alias to a constant value or a type.

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 name (Type1, Type2, ...)
import function 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

Global Variables

global name = value

Creates a global variable.

To create a global variable without initialized data:

global v1 = {Int32}    // uninitialized integer
global v2 = {MyStruct} // pointer to an uninitialized structure on heap
global v2 = {*MyStruct} // uninitialized pointer to a structure

Local Variables

var name = value

Defines a local variable in a function or a method.

To create a local variable without initial value:

var v1 = {Int32}    // uninitialized integer
var v2 = {MyStruct} // pointer to an uninitialized structure on stack
var v2 = {*MyStruct} // uninitialized pointer to a structure