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 begin break case cond const continue defer do else elsif end extend function if import meta 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 Uint8 Uint16 Uint32 Uint64
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
Name | Description |
---|---|
Uint8 | unsigned 8 bit integer |
Uint16 | unsigned 16 bit integer |
Uint32 | unsigned 32 bit integer |
Uint64 | unsigned 64 bit integer |
Int8 | signed 8 bit integer |
Int16 | signed 16 bit integer |
Int32 | signed 32 bit integer |
Int64 | signed 64 bit integer |
Size | unsigned integer with the size of a pointer |
Bool | boolean type |
Anything | special type matching all types |
Nil | the 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:
Character | Description |
---|---|
\a | Bell (7) |
\b | Backspace (8) |
\f | Form Feed (12) |
\n | Line Feed (10) |
\r | Cariage Return (13) |
\t | Tab (9) |
\v | Vertical Tab (11) |
\w | Whitespace (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
Operator | Description |
---|---|
& | and |
| | or |
^ | exclusive or |
<< | left shift |
>> | right shift |
and | and, eval 2nd expr if and only if 1st is true |
or | or, 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
Yield
yield yield e1 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. 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
The yield expression can return one or more values if the block returns one or more values using continue.
Builtin Functions
Type size
Returns the size in bytes of the type.
Type super
Returns the parent type. If the type has no parent, it will generate an error.
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.
Structure vtable (Type)
Returns an initializer for the given structure that is automatically initialized using the Type. 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 function. 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.
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 break e1 break e1, e2, ..., en
The break statement interrupts a while or repeat loop.
The break statement can also be used to interrupt a function when invoked from a block passed to a function.
Continue
continue continue e1 continue e1, e2, ..., en
The continue statement interrupts the execution of a block passed to a function.
The arguments are returned to the function.
Return
return return e1 return e1, e2, ..., en
Returns zero, one or more values from a function.
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
Defer
defer aStatement
The statement will be executed when leaving the current block, either on normal exit, on return or on break.
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
Name | Operation |
---|---|
_add | + |
_sub | - |
_mul | * |
_div | / |
_mod | % |
_shl | << |
_shr | >> |
_eq | == |
_ne | <> |
_le | <= |
_lt | < |
_ge | >= |
_gt | > |
_and | & |
_xor | ^ |
_or | | |
_not | not |
_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
- Instance variables
- Instance functions
- Static declarations
- Class declarations
- Imported instance, static and class functions
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
var name: Type
An attribute is accessed with the same syntax as a method without parameter:
aStruct name
Methods
function [+] 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.
Static Definitions
static decl
static is a prefix to declare a global variable, constant, function, structure or sub-type inside a type. The definition will be visible only from this type.
Class Definitions
meta decl
meta is a prefix to declare a class instance variable, a constant, function, structure or sub-type inside a type. The definition will be a property of the type.
e.g.:
struct Point var x : Integer var y : Integer meta function new var pt = Point allocate pt x = 0 pt y = 0 return pt end end function test var pt = Point new end
Enumerations and Sub-types
stype name [: Type] 'item1 [= value1] 'item2 [= value2] ... function name1 (...) ... end
Defines a derived type of Type. The parent must be a simple type: either a pointer, an integer or a boolean. 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.
e.g.:
stype String : *[]Uint8 function 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 a class function:
import meta function ["public-name"] name (Type1, Type2, ...) import meta function ["public-name"] name (Type1, Type2, ...) -> (R1, R2, ...)
To import a static function:
import static function ["public-name"] name (Type1, Type2, ...) import static function ["public-name"] name (Type1, Type2, ...) -> (R1, R2, ...)
Extend
extend Type
It allows to add methods to any existing type.
e.g.:
extend Int32 function 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 var name : Type, id (e1, e2, ...)
Defines a local variable in a function or a method with or without an initial value.
The last form will create a variable of type Type on the stack and will initialize it using id and will relase it when leaving the current block. This is strictly equivalent to:
var name : Type name id (e1, e2, ...) defer name release