Introduction. #
-Cyber is a fast, efficient, and concurrent scripting language. The landing page is at cyberscript.dev and contains performance metrics and release notes.
+Cyber is a fast, efficient, and concurrent scripting language. The landing page is at cyberscript.dev and contains performance metrics and release notes.
Cyber is easy to learn. These docs provide a reference manual for the language. You can read it in order or jump around using the navigation.
You may come across features that are marked Incomplete
or Planned
. This is because the docs are written as if all features have been completed already.
Hello World. #
-import math
+$(htmlContent) #
+import math
var worlds = ['World', '世界', 'दुनिया', 'mundo']
worlds.append(math.random())
for worlds -> w:
- print 'Hello, $(w)!'
+ print "Hello, $(w)!"
-Syntax. #
+^topic
+$(htmlContent) #
-
+
Cyber's syntax is concise and easy to read.
-Statements. #
-A statement ends with the new line.
--- An assignment statement.
-var a = 123
+$(htmlContent) #
+A statement ends with the new line:
+var a = 123
+
+To wrap a statement to the next line, the last token before the new line must be an operator or a separator:
+var gameover = health <= 0 or
+ player.collidesWith(spikes)
+
+if year > 2020 and year <= 2030 and
+ month > 0 and month <= 11:
+ print 'Valid'
-
-Blocks. #
+Any token inside a delimited syntax (such as parentheses or brackets) can be wrapped to the next line:
+var sum = add(1, 2, 3, 4,
+ 100, 200, 300, 400)
+
+var colors = ['red', 'blue', 'green',
+ 'purple', 'orange', 'yellow']
+
+^topic
+$(htmlContent) #
Some statements can start a new block with a colon.
The first statement in a new block must be indented further.
Spaces or tabs can be used for indentation but not both.
--- This `if` statement begins a new block.
+-- This `if` statement begins a new block.
if true:
var a = 234
Subsequent statements in the block must follow the same indentation.
-The block ends when a statement recedes from this indentation.
-var items = [10, 20, 30]
+The block ends when a statement recedes from this indentation:
+var items = [10, 20, 30]
for items -> it:
if it == 20:
print it
print it -- This is the first statement outside of the `if` block.
-Single-line blocks allow only one statement after a starting block.
--- A single line block.
+Compact blocks allow only one statement after the starting block:
+-- A single line block.
if true: print 123
if true: print 123
- -- This is an indentation error since the single-line block is already consumed.
+ -- This is an indentation error since the compact block is already consumed.
print 234
-Since blocks require at least one statement, use pass
as a placeholder statement.
-func foo():
+Since blocks require at least one statement, use pass
as a placeholder statement:
+func foo():
pass
-
-Variables. #
+^topic
+$(htmlContent) #
Cyber supports dynamic and static typing. If you're used to a dynamic language such as Python, JavaScript, or Lua, use my
to declare your variables and object fields. If you're used to a static language then use var
instead. The documentation will use static typing by default.
-
-Local variables. #
+^topic
+$(htmlContent) #
Local variables exist until the end of their scope.
They are declared and initialized using the var
keyword:
-var a = 123
+var a = 123
When declared without a type specifier next to the variable, it infers the type from the right initializer.
-To declare variables for a specific type, see Typed variables.
+To declare variables for a specific type, see Typed variables.
Variables can be set afterwards using the =
operator:
-a = 234
+a = 234
-
-Dynamic variables. #
+^topic
+$(htmlContent) #
Dynamically typed variables are easier to work with and there is no friction when using them. They are declared using the my
keyword:
-my a = 123
+my a = 123
-To understand more about dynamically and statically typed code, see Type System.
-
-Variable scopes. #
+To understand more about dynamically and statically typed code, see Type System.
+^topic
+$(htmlContent) #
Blocks create a new variable scope. Variables declared in the current scope will take precedence over any parent variables with the same name:
-func foo():
+func foo():
var a = 234
if true:
@@ -1140,99 +1155,94 @@ Variable scopes. #
print a -- Prints "234"
-
-Static Variables. #
+^topic
+$(htmlContent) #
Static variables live until the end of the script.
They act as global variables and are visible from anywhere in the script.
They are declared with var
but a namespace must be provided before the variable name:
-var Root.a = 123
+var .a = 123
func foo():
print a -- '123'
-The Root
symbol is used to reference the current module's namespace.
+The .
prefix is used to reference the current module's namespace.
Since static variables are initialized outside of a fiber's execution flow, they can not reference any local variables:
--- Static declaration.
-var Root.b = a -- Compile error, initializer can not reference a local variable.
+-- Static declaration.
+var .b = a -- Compile error, initializer can not reference a local variable.
-- Main execution.
var a = 123
However, they can be reassigned after initialization:
-var Root.b = 0
+var .b = 0
var a = 123
b = a -- Reassigning after initializing.
Static variable initializers have a natural order based on when it was encountered by the compiler.
-In the case of imported variables, the order of the import would affect this order.
+In the case of imported variables, the order of the import would affect this order.
The following would print '123' before '234':
-var Root.a = print(123)
-var Root.b = print(234)
+var .a = print(123)
+var .b = print(234)
When the initializers reference other static variables, those child references are initialized first in DFS order and supersede the natural ordering. The following initializes b
before a
.
-var Root.a = b + 321
-var Root.b = 123
+var .a = b + 321
+var .b = 123
print a -- '444'
Circular references in initializers are not allowed.
When initialization encounters a reference that creates a circular dependency an error is reported.
-var Root.a = b
-var Root.b = a -- CompileError. Referencing `a` creates a circular dependency.
+var .a = b
+var .b = a -- CompileError. Referencing `a` creates a circular dependency.
Sometimes, you may want to initialize a static variable by executing multiple statements in order.
For this use case, you can use a declaration block. Planned Feature
-var Root.myImage =:
+var .myImage =:
var img = loadImage('me.png')
img.resize(100, 100)
img.filter(.blur, 5)
break img
The final resulting value that is assigned to the static variable is provided by a break
statement. If a break
statement is not provided, none
is assigned instead.
-
-Reserved identifiers. #
-Keywords. #
+^topic
+$(htmlContent) #
+^topic
+$(htmlContent) #
There are 25
general keywords. This list categorizes them:
-- Control Flow:
if
else
switch
case
while
for
break
continue
pass
-- Operators:
or
and
not
-- Variables:
var
my
-- Functions:
func
return
-- Coroutines:
coinit
coyield
, coresume
-- Data Types:
type
as
-- Error Handling:
try
catch
throw
-- Modules:
import
+- Control Flow:
if
else
switch
case
while
for
break
continue
pass
+- Operators:
or
and
not
+- Variables:
var
my
+- Functions:
func
return
+- Coroutines:
coinit
coyield
, coresume
+- Data Types:
type
as
+- Error Handling:
try
catch
throw
+- Modules:
import
-
-Contextual keywords. #
+^topic
+$(htmlContent) #
These keywords only have meaning in a certain context.
-- Methods:
self
, Self
-- Catching Errors:
caught
-- Object Type:
object
-- Enum Type:
enum
-- Function Throws:
throws
+- Methods:
self
, Self
+- Catching Errors:
caught
+- Enum Type:
enum
+- Function Throws:
throws
-
-Symbols. #
+^topic
+$(htmlContent) #
-- Modules:
Root
+- Booleans:
true
false
+- Error Values:
error
+- None:
none
-
-Literals. #
-
-- Booleans:
true
false
-- Error Values:
error
-- None:
none
-
-
-Operators. #
+^topic
+$(htmlContent) #
Cyber supports the following operators. They are ordered from highest to lowest precedence.
-Operator Description <<
>>
Bitwise left shift, right shift. &
Bitwise and. \|
\|\|
Bitwise or, exclusive or. ^
Power. /
%
*
Division, modulus, multiplication. +
-
Addition, subtraction. as
Type casting. >
>=
<
<=
!=
==
Greater, greater or equal, less, less or equal, not equals, equals. and
Logical and. or
Logical or.
-Arithmetic Operators. #
-The following arithmetic operators are supported for the numeric data types.
-1 + 2 -- Addition, evaluates to 3.
+Operator Description <<
>>
Bitwise left shift, right shift. &
Bitwise and. |
||
Bitwise or, exclusive or. ^
Power. /
%
*
Division, modulus, multiplication. +
-
Addition, subtraction. as
Type casting. >
>=
<
<=
!=
==
Greater, greater or equal, less, less or equal, not equals, equals. and
Logical and. or
Logical or.
^topic
+$(htmlContent) #
+The following arithmetic operators are supported for the numeric data types.
+1 + 2 -- Addition, evaluates to 3.
100 - 10 -- Subtraction, evaluates to 90.
3 * 4 -- Multiplication, evaluates to 12.
20 / 5 -- Division, evaluates to 4.
@@ -1240,12 +1250,12 @@ Arithmetic Operators. parent
-Comparison Operators. #
+^topic
+$(htmlContent) #
Cyber supports the following comparison operators.
-By default, a comparison operator evaluates to a Boolean value.
+By default, a comparison operator evaluates to a Boolean value.
The equals operator returns true if the two values are equal. For primitive types, the comparison checks the types and the underlying value. For strings, the underlying bytes are compared for equality. For objects, the comparison checks that the two values reference the same object.
-1 == 1 -- Evaluates to `true`
+1 == 1 -- Evaluates to `true`
1 == 2 -- Evaluates to `false`
1 == true -- Evaluates to `false`
@@ -1258,41 +1268,41 @@ Comparison Operators. 1 != 1 -- Evaluates to `false`
+1 != 1 -- Evaluates to `false`
1 != 2 -- Evaluates to `true`
Number types have additional comparison operators.
-a > b -- `true` if a is greater than b
+a > b -- `true` if a is greater than b
a >= b -- `true` if a is greater than or equal to b
a < b -- `true` if a is less than b
a <= b -- `true` if a is less than or equal to b
-
-Logic Operators. #
+^topic
+$(htmlContent) #
The logical operators and
, or
, and not
are supported.
and
evaluates to a
if a
is not truthy. Otherwise, it evaluates to b
. If a
is not truthy, the evaluation of b
is not executed. A numeric value that isn't 0 is truthy. An object reference is always truthy. The none value is not truthy.
-true and true -- Evaluates to true
+true and true -- Evaluates to true
123 and 234 -- Evaluates to 234
123 and 0 -- Evaluates to false
or
evaluates to a
if a
is truthy. Otherwise, it evaluates to b
. If a
is found to be truthy, the evaluation of b
is not executed.
-true or false -- Evaluates to true
+true or false -- Evaluates to true
false or true -- Evaluates to true
false or false -- Evaluates to false
123 or false -- Evaluates to 123
The unary operator not
performs negation on the boolean value. The unary operator !
can also be used instead of not
.
-not false -- Evaluates to true
+not false -- Evaluates to true
not true -- Evaluates to false
not 0 -- Evaluates to true
not 123 -- Evaluates to false
!false -- Evaluates to true
!true -- Evaluates to false
-
-Bitwise Operators. #
+^topic
+$(htmlContent) #
The following bitwise operators are supported for int
number values.
--- Bitwise and: any underlying bits that are set in both integers are set in the new integer.
+-- Bitwise and: any underlying bits that are set in both integers are set in the new integer.
a & b
-- Bitwise or: any underlying bits that are set in either integer a or integer b are set in the new integer.
@@ -1310,21 +1320,21 @@ Bitwise Operators. #
-- Bitwise not: a's integer bits are flipped.
~a
-
-Operator overloading. #
-See Operator overloading in Metaprogramming.
-
-Comments. #
+^topic
+$(htmlContent) #
+See Operator overloading in Metaprogramming.
+^topic
+$(htmlContent) #
A single line comment starts with two hyphens and ends at the end of the line.
--- This is a comment.
+-- This is a comment.
var a = 123 -- This is a comment on the same line as a statement.
There will be multi-line comments in Cyber but the syntax has not been determined.
-
-CYON. #
+^topic
+$(htmlContent) #
CYON or the Cyber object notation is similar to JSON. The format uses the same literal value semantics as Cyber.
-[
+[
name: 'John Doe',
'age': 25,
-- This is a comment
@@ -1335,64 +1345,70 @@ CYON. #
],
]
-
-Data Types. #
+^topic
+$(htmlContent) #
-
+
In Cyber, there are primitive types and object types. Primitives are copied around by value and don't need additional heap memory or reference counts.
-Primitives include Booleans, Floats, Integers, Enums, Symbols, Error Values, and the none
value.
-Object types include Lists, Tuples, Maps, Strings, Arrays, User Objects, Lambdas, Fibers, Enums with payloads, Pointers, and several internal object types.
-None. #
+Primitives include Booleans, Floats, Integers, Enums, Symbols, Error Values, and the none
value.
+Object types include Lists, Tuples, Maps, Strings, Arrays, User Objects, Lambdas, Fibers, Enums with payloads, Pointers, and several internal object types.
+$(htmlContent) #
The none
value represents an empty value. This is similar to null in other languages.
-
-Booleans. #
-Booleans can be true
or false
. See type bool
.
-var a = true
+^topic
+$(htmlContent) #
+Booleans can be true
or false
. See type bool
.
+var a = true
if a:
print 'a is true'
@@ -1401,92 +1417,95 @@ Booleans. #
The none
value is false
.
Other objects and values are always true
.
-
-Numbers. #
-Integers. #
-int
is the default integer type. It has 48-bits and can represent integers in the range -(247) to 247-1. See type int
.
+^topic
+$(htmlContent) #
+^topic
+$(htmlContent) #
+int
is the default integer type. It has 48-bits and can represent integers in the range -(247) to 247-1. See type int
.
When a numeric literal is used and the type can not be inferred, it will default to the int
type:
-var a = 123
+var a = 123
Integer notations always produce a int
value:
-var a = 0xFF -- hex.
+var a = 0xFF -- hex.
a = 0o17 -- octal.
a = 0b1010 -- binary.
a = `🐶` -- UTF-8 rune.
Arbitrary values can be converted to a int
using the type as a function.
-var a = '123'
+var a = '123'
var b = int(a)
-In addition to arithmetic operations, integers can also perform bitwise operations.
-
-Floats. #
-float
is the default floating point type. It has a (IEEE 754) 64-bit floating point format. See type float
.
+In addition to arithmetic operations, integers can also perform bitwise operations.
+^topic
+$(htmlContent) #
+float
is the default floating point type. It has a (IEEE 754) 64-bit floating point format. See type float
.
Although a float
represents a decimal number, it can also represent integers between -(253-1) and (253-1). Any integers beyond the safe integer range is not guaranteed to have a unique representation.
A numeric literal can be used to create a float
if the inferred type is a float
:
-var a float = 123
+var a float = 123
Decimal and scientific notations always produce a float
value:
-var a = 2.34567
+var a = 2.34567
var b = 123.0e4
Arbitrary values can be converted to a float
using the type as a function.
-var a = '12.3'
+var a = '12.3'
var b = float(a)
-
-Big Numbers. #
+^topic
+$(htmlContent) #
Planned Feature
-
-Strings. #
-The string
type represents a sequence of UTF-8 codepoints, also known as runes
. Each rune is stored internally as 1-4 bytes and can be represented as an int
. See type string
.
-Under the hood, there are multiple string implementations to make operations faster by default.
-Strings are immutable, so operations that do string manipulation return a new string. By default, small strings are interned to reduce memory footprint.
-To mutate an existing string, use MutString. Planned Feature
-A string is always UTF-8 validated. Using an Array to represent raw bytes of a string is faster but you'll have to validate them and take care of indexing.
-A single line string literal is surrounded in single quotes.
-var apple = 'a fruit'
-
-You can escape the single quote inside the literal or use double quotes.
-var apple = 'Bob\'s fruit'
-apple = "Bob's fruit"
-
+^topic
+$(htmlContent) #
+The string
type represents a sequence of validated UTF-8 codepoints, also known as runes
. Each rune is stored internally as 1-4 bytes and can be represented as an int
. See type string
.
+Strings are immutable, so operations that do string manipulation return a new string. By default, short strings are interned to reduce memory footprint.
+Under the hood, there are multiple string implementations to make operations faster by default using SIMD.
+^topic
+$(htmlContent) #
+A raw string doesn't allow any escape sequences or string interpolation.
+Single quotes are used to delimit a single line literal:
+var fruit = 'apple'
+var str = 'abc🦊xyz🐶'
+
+Since raw strings interprets the sequence of characters as is, a single quote character can not be escaped:
+var fruit = 'Miso's apple' -- ParseError.
+
+Triple single quotes are used to delimit a multi-line literal. It also allows single quotes and double single quotes in the string:
+var fruit = '''Miso's apple'''
+var greet = '''Hello
+World'''
+
+^topic
+$(htmlContent) #
+A string literal allows escape sequences and string interpolation.
+Double quotes are used to delimit a single line literal:
+var fruit = "apple"
+var sentence = "The $(fruit) is tasty."
+var doc = "A double quote can be escaped: \""
+
+Triple double quotes are used to delimit a multi-line literal:
+var title = "last"
+var doc = """A double quote " doesn't need to be escaped."""
+str = """line a
+line "b"
+line $(title)
+"""
+
+^topic
+$(htmlContent) #
+The following escape sequences are supported in string literals:
+Escape Sequence Code Description \a 0x07 Terminal bell. \b 0x08 Backspace. \e 0x1b Escape character. \n 0x0a Line feed character. \r 0x0d Carriage return character. \t 0x09 Horizontal tab character.
^topic
+$(htmlContent) #
+See type string
for all available methods.
Concatenate two strings together with the +
operator or the method concat
.
-var res = 'abc' + 'xyz'
+var res = 'abc' + 'xyz'
res = res.concat('end')
-Strings are UTF-8 encoded.
-var str = 'abc🦊xyz🐶'
-
-Use double quotes to surround a multi-line string.
-var str = "line a
-line b
-line c"
-
-You can escape double quotes inside the literal or use triple quotes.
-var str = "line a
-line \"b\"
-line c"
-
--- Using triple quotes.
-str = '''line a
-line "b"
-line c
-'''
-
-The following escape sequences are supported:
-Escape Sequence Code Description \a 0x07 Terminal bell. \b 0x08 Backspace. \e 0x1b Escape character. \n 0x0a Line feed character. \r 0x0d Carriage return character. \t 0x09 Horizontal tab character.
The boundary of each line can be set with a vertical line character. This makes it easier to see the whitespace.
-Planned Feature
-var poem = "line a
- | two spaces from the left
- | indented further"
-
Using the index operator will return the UTF-8 rune at the given index as a slice. This is equivalent to calling the method sliceAt()
.
-var str = 'abcd'
+var str = 'abcd'
print str[1] -- "b"
Using the slice operator will return a view of the string at the given start and end (exclusive) indexes. The start index defaults to 0 and the end index defaults to the string's length.
-var str = 'abcxyz'
+var str = 'abcxyz'
var sub = str[0..3]
print sub -- "abc"
print str[..5] -- "abcxy"
@@ -1499,60 +1518,84 @@ Strings. #
i += 1
print(i + str[i..].findRune(`c`)) -- "5"
-
-String Interpolation. #
+^topic
+$(htmlContent) #
Expressions can be embedded into string templates with $()
:
-var name = 'Bob'
+var name = 'Bob'
var points = 123
-var str = 'Scoreboard: $(name) $(points)'
+var str = "Scoreboard: $(name) $(points)"
String templates can not contain nested string templates.
-
-String formatting. #
+^topic
+$(htmlContent) #
Values that can be formatted into a string will have a fmt
method:
-var file = os.openFile('data.bin', .read)
+var file = os.openFile('data.bin', .read)
var bytes = file.readToEnd()
-- Dump contents in hex.
-print '$(bytes.fmt(.x))'
+print "$(bytes.fmt(.x))"
-
-Arrays. #
-An array
is an immutable sequence of bytes. It can be used to represent strings but it won't automatically validate their encoding and indexing returns the n'th byte rather than a UTF-8 rune. See type array
.
-var a = array('abcd')
+^topic
+$(htmlContent) #
+The line-join literal joins string literals with the new line character \n
. Planned Feature
+This has several properties:
+
+- Ensures the use of a consistent line separator:
\n
+- Allows lines to have a mix of raw string or string literals.
+- Single quotes and double quotes do not need to be escaped.
+- Allows each line to be indented along with the surrounding syntax.
+- The starting whitespace for each line is made explicit.
+
+var paragraph = [
+ \'the line-join literal
+ \'hello\nworld
+ \"hello $(name)
+ \'last line
+ \'
+]
+
+^topic
+$(htmlContent) #
+To mutate an existing string, use type MutString. Planned Feature
+^topic
+$(htmlContent) #
+An array
is an immutable sequence of bytes.
+It can be a more performant way to represent strings but it won't automatically validate their encoding and indexing returns the n'th byte rather than a UTF-8 rune.
+See type array
.
+var a = array('abcd')
a = a.insertByte(1, 255)
print a[0] -- "97"
print a[1] -- "255"
-
-Bracket literals. #
+^topic
+$(htmlContent) #
Bracket literals are delimited with brackets []
. They are used to initialize Lists, Maps, and Objects:
-var list = [1, 2, 3]
+var list = [1, 2, 3]
var map = [ a: 123, b: 234 ]
var obj = [MyObject a: 123, b: 234]
-
-Lists. #
-Lists are a builtin type that holds an ordered collection of elements. Lists grow or shrink as you insert or remove elements. See type List
.
--- Construct a new list.
+^topic
+$(htmlContent) #
+Lists are a builtin type that holds an ordered collection of elements. Lists grow or shrink as you insert or remove elements. See type List
.
+-- Construct a new list.
var list = [1, 2, 3]
-- The first element of the list starts at index 0.
print list[0] -- Prints '1'
Lists can be sliced with the range ..
clause. The sliced list becomes a new list that you can modify without affecting the original list. The end index is non-inclusive.
-var list = [ 1, 2, 3, 4, 5 ]
+var list = [ 1, 2, 3, 4, 5 ]
list[0..0] -- []
list[0..3] -- [ 1, 2, 3 ]
list[3..] -- [ 4, 5 ]
list[..3] -- [ 1, 2, 3 ]
The +..
invokes the slice operator with an end position that is an increment from the start: Planned Feature
-var list = [ 1, 2, 3, 4, 5 ]
+var list = [ 1, 2, 3, 4, 5 ]
list[2+..2] -- [ 3, 4 ]
List operations.
-var list = [234]
+var list = [234]
-- Append a value.
list.append 123
@@ -1573,39 +1616,39 @@ Lists. #
-- Remove an element at a specific index.
list.remove(1)
-
-Tuples. #
-Incomplete: Tuples can only be created from @host funcs at the moment.
-
-Maps. #
-Maps are a builtin type that store key value pairs in dictionaries. See type Map
.
-
-Create map. #
+^topic
+$(htmlContent) #
+Incomplete: Tuples can only be created from #host funcs at the moment.
+
^topic
+$(htmlContent) #
+Maps are a builtin type that store key value pairs in dictionaries. See type Map
.
+^topic
+$(htmlContent) #
Create a map using key value pairs inside a collection literal:
-var map = [ a: 123, b: () => 5 ]
+var map = [ a: 123, b: () => 5 ]
Maps entries can be listed in multiple lines:
-var map = [
+var map = [
foo: 1,
bar: 2,
]
-
-Empty map. #
+^topic
+$(htmlContent) #
The empty map is initialized using [:]
:
-var empty = [:]
+var empty = [:]
-
-Map indexing. #
+^topic
+$(htmlContent) #
Get a value from the map using the index operator:
-print map['a']
+print map['a']
Maps can be accessed with the .
dot operator as well:
-print map.a
+print map.a
-
-Map operations. #
-var map = [:]
+^topic
+$(htmlContent) #
+var map = [:]
-- Set a key value pair.
map[123] = 234
@@ -1618,15 +1661,15 @@ Map operations. #
-- Iterating a map.
for map -> [val, key]:
- print '$(key) -> $(val)'
+ print "$(key) -> $(val)"
-
-Map block. #
+^topic
+$(htmlContent) #
Entries can also follow a collection literal block.
This gives structure to the entries and has
the added benefit of allowing multi-line lambdas.
Planned Feature
-var colors = []:
+var colors = []:
red: 0xFF0000
green: 0x00FF00
blue: 0x0000FF
@@ -1641,29 +1684,29 @@ Map block. #
green: 0x00AA00
blue: 0x0000AA
-
-Objects. #
-Any value that isn't a primitive is an object. You can declare your own object types using the type object
declaration.
+^topic
+$(htmlContent) #
+
Any value that isn't a primitive is an object. You can declare your own object types using the type
declaration.
Object types are similar to structs and classes in other languages.
Unlike classes, there is no concept of inheritance at the language level.
-
-Fields. #
-Fields must be declared at the top of the type object
block using var
or my
:
-type Node object:
+^topic
+$(htmlContent) #
+Fields must be declared at the top of the type
block using var
or my
:
+type Node:
var value int
var next any
When fields are declared with my
instead, they become dynamically typed.
-
-Instantiation. #
+^topic
+$(htmlContent) #
New object instances are created using a leading type name and the field values in a collection literal:
-var node = [Node value: 123, next: none]
+var node = [Node value: 123, next: none]
print node.value -- Prints "123"
-
-Methods. #
+^topic
+$(htmlContent) #
Methods allow invoking a function on an object instance using the .
operator:
-type Node object:
+type Node:
var value int
var next any
@@ -1678,24 +1721,24 @@ Methods. #
n.incAndPrint() -- Prints "444"
Methods can also be declared outside of the type declaration. To distinguish a method from a type function, self
must be provided as a parameter:
-func Node.getNext(self):
+func Node.getNext(self):
return self.next
-
-self
variable. #
+^topic
+$(htmlContent) #
Type members can be implicitly referenced inside the method. Incomplete: Only the type's fields can be referenced this way.
To reference members explicitly inside a method, use the builtin self
:
-type Node object:
+type Node:
var value int
var next any
func double():
return self.value * 2
-
-Type functions. #
+^topic
+$(htmlContent) #
Type functions are declared outside of the type
block with an explicit namespace path:
-type Node object:
+type Node:
var value int
var next any
@@ -1705,20 +1748,20 @@ Type functions. #
var n = Node.new()
-
-Type variables. #
+^topic
+$(htmlContent) #
Similarily, type variables are declared outside of the type
block:
--- Declare inside the `Node` namespace.
+-- Declare inside the `Node` namespace.
var Node.DefaultValue = 100
print Node.DefaultValue -- Prints "100"
-
-Enums. #
+^topic
+$(htmlContent) #
A new enum type can be declared with the type enum
declaration.
An enum value can only be one of the unique symbols declared in the enum type.
By default, the symbols generate unique ids starting from 0.
-type Fruit enum:
+type Fruit enum:
case apple
case orange
case banana
@@ -1729,58 +1772,59 @@ Enums. #
print int(fruit) -- '3'
When the type of the value is known to be an enum, it can be assigned using a symbol literal.
-var fruit = Fruit.kiwi
+var fruit = Fruit.kiwi
fruit = .orange
print(fruit == Fruit.orange) -- 'true'
-
-Symbols. #
+^topic
+$(htmlContent) #
Symbol literals begin with .
, followed by an identifier. They have their own global unique id.
-var currency = .usd
+var currency = .usd
print(currency == .usd) -- 'true'
print int(currency) -- '123' or some arbitrary id.
-
-Control Flow. #
+^topic
+$(htmlContent) #
-
+
Cyber provides the common constructs to branch and enter loops.
-Branching. #
-if
statement. #
+$(htmlContent) #
+^topic
+$(htmlContent) #
Use if
and else
statements to branch the execution of your code depending on conditions. The else
clause can contain a condition which is only evaluated if the previous if or conditional else clause was false
.
-var a = 10
+var a = 10
if a == 10:
print 'a is 10'
else a == 20:
@@ -1788,116 +1832,117 @@ if
statement. #
else:
print 'neither 10 nor 20'
-
-Conditional expression. #
+^topic
+$(htmlContent) #
A conditional branch expression evaluates a condition and returns either the true value or false value:
-var a = 10
+var a = 10
var str = a == 10 ? 'red' else 'blue'
-
-and
/or
#
+^topic
+$(htmlContent) #
Use and
and or
logical operators to combine conditions:
-var a = 10
+var a = 10
if a > 5 and a < 15:
print 'a is between 5 and 15'
if a == 20 or a == 10:
print 'a is 10 or 20'
-
-Iterations. #
-Infinite loop. #
+^topic
+$(htmlContent) #
+^topic
+$(htmlContent) #
The while
keyword starts an infinite loop which continues to run the code in the block until a break
or return
is reached.
-var count = 0
+var count = 0
while:
if count > 100:
break
count += 1
-
-Conditional loop. #
+^topic
+$(htmlContent) #
When the while
clause contains a condition, the loop continues to run until the condition is evaluated to false
:
-var running = true
+var running = true
var count = 0
while running:
if count > 100:
running = false
count += 1
-
-Unwrapping loop. #
+^topic
+$(htmlContent) #
Using the capture operator ->
unwraps the left optional value to the right variable declaration. The loop exits when the left value is none
:
-var iter = dir.walk()
+var iter = dir.walk()
while iter.next() -> entry:
print entry.name
-
-for
range. #
+^topic
+$(htmlContent) #
for
loops can iterate over a range that starts at an int
(inclusive) to a target int
(exclusive).
The capture operator ->
is used to capture the loop's counter variable:
-for 0..4:
+for 0..4:
performAction()
for 0..100 -> i:
print i -- 0, 1, 2, ... , 99
To decrement the counter instead, use -..
:
-for 100-..0 -> i:
+for 100-..0 -> i:
print i -- 100, 99, 98, ... , 1
When the range operator ..
is replaced with ..=
, the target int
is inclusive: Planned Feature
-for 0..=100 -> i:
+for 0..=100 -> i:
print i -- 0, 1, 2, ... , 100
-
-for
each. #
+^topic
+$(htmlContent) #
The for
clause can iterate over any type that implements the Iterable
trait. An Iterable contains an iterator()
method which returns an Iterator
object. The for loop continually invokes the Iterator's next()
method until none
is returned.
Lists can be iterated since they implement the Iterable trait. The capture operator ->
is used to capture the value returned from an iterator's next()
:
-var list = [1, 2, 3, 4, 5]
+var list = [1, 2, 3, 4, 5]
for list -> n:
print n
Maps can be iterated. next()
returns a key and value tuple:
-var map = [ a: 123, b: 234 ]
+var map = [ a: 123, b: 234 ]
for map -> entry:
print entry[0]
print entry[1]
Use the destructure syntax to extract the key and value into two separate variables:
-for map -> [ key, val ]:
- print 'key $(key) -> value $(val)'
+for map -> [ key, val ]:
+ print "key $(key) -> value $(val)"
-
-for
each with index. #
+^topic
+$(htmlContent) #
A counting index can be declared after the each variable. The count starts at 0 for the first value:
-var list = [1, 2, 3, 4, 5]
+var list = [1, 2, 3, 4, 5]
for list -> val, i:
- print 'index $(i), value $(val)'
+ print "index $(i), value $(val)"
-
-Exit loop. #
+^topic
+$(htmlContent) #
Use break
to exit a loop. This loop stops printing once i
reaches 4:
-for 0..10 -> i:
+for 0..10 -> i:
if i == 4:
break
print i
-
-Next iteration. #
+^topic
+$(htmlContent) #
Use continue
to skip the rest of the loop and go to the next iteration.
This loop prints 0 through 9 but skips 4:
-for 0..10 -> i:
+for 0..10 -> i:
if i == 4:
continue
print i
-
-switch
matching. #
+^topic
+$(htmlContent) #
The switch
statement branches to a case block from a matching case condition. The expression that is matched against comes after switch statement. Multiple cases can be grouped together using a comma separator. An optional else
fallback case is executed when no other cases were matched.
Incomplete: Not all types can be used in the case conditions such as ranges.
-var val = 1000
+var val = 1000
switch val:
case 0..100: print 'at or between 0 and 99'
case 100 : print 'val is 100'
@@ -1906,57 +1951,57 @@ switch
matching.
Note that the switch
block must be empty and requires at least one case
block or an else
block to come after it.
-
-switch
assignment. #
+^topic
+$(htmlContent) #
Although switch
can not be used freely as an expression, it can be assigned to a left variable or destination:
-var shu = switch pepper:
+var shu = switch pepper:
case 'bell' => 0
case 'anaheim' => 500
case 'jalapeño' => 2000
case 'serrano' => 10000
When declaring an assignable switch, the cases must have a return value using the syntax case {cond} => {expr}
or else => {expr}
.
-
-switch
break. #
+^topic
+$(htmlContent) #
A break
statement exits the current case block and resumes execution after the end of the switch statement: Planned Feature
-switch value:
+switch value:
case 0..5:
print value
if value == 3:
break case
print value -- Skips second print if `value` is 3.
-
-Try/Catch. #
-The try catch
statement, try else
and try
expressions provide a way to catch a throwing error and resume execution in a different branch. Learn more about Error Handling.
-
-Deferred Execution. #
+^topic
+$(htmlContent) #
+The try catch
statement, try else
and try
expressions provide a way to catch a throwing error and resume execution in a different branch. Learn more about Error Handling.
+^topic
+$(htmlContent) #
Planned Feature
-
-Functions. #
+^topic
+$(htmlContent) #
-- Static functions.
-- Function overloading.
-- Lambdas.
-- Closures.
-- Named parameters.
-- Optional parameters.
-- Variadic parameters.
-- Function calls.
-- Shorthand syntax.
-- Call block syntax.
+- Static functions.
+- Function overloading.
+- Lambdas.
+- Closures.
+- Named parameters.
+- Optional parameters.
+- Variadic parameters.
+- Function calls.
-
+
In Cyber, there are first-class functions (or function values) and static functions.
-Static functions. #
+$(htmlContent) #
Static functions are not initially values themselves. They allow function calls to be optimal since they don't need to resolve a dynamic value.
Static functions are declared with the func
keyword and must have a name.
-import math
+import math
func dist(x0 float, y0 float, x1 float, y1 float) float:
var dx = x0-x1
@@ -1964,7 +2009,7 @@ Static functions. #
Calling static functions is straightforward. You can also reassign or pass them around as function values.
-print dist(0, 0, 10, 20)
+print dist(0, 0, 10, 20)
-- Assigning to a local variable.
var bar = dist
@@ -1976,17 +2021,17 @@ Static functions. #
Functions can only return one value. However, the value can be destructured: Planned Feature
-import {cos, sin} 'math'
+import {cos, sin} 'math'
func compute(rad):
return [ cos(rad), sin(rad) ]
var [ x, y ] = compute(pi)
-
-Function overloading. #
-Functions can be overloaded by the number of parameters in its signature. Typed functions are further overloaded by their type signatures.
-func foo():
+^topic
+$(htmlContent) #
+Functions can be overloaded by the number of parameters in its signature. Typed functions are further overloaded by their type signatures.
+func foo():
return 2 + 2
func foo(n):
@@ -1999,11 +2044,11 @@ Function overloading.
-
-Lambdas. #
+^topic
+$(htmlContent) #
Lambdas or function values can be assigned to variables or passed as arguments into other constructs.
When a lambda only returns an expression, it can be declared with a simplified syntax.
--- Passing simple lambda as an argument.
+-- Passing simple lambda as an argument.
foo(word => toUpper(word))
-- A simple lambda with multiple arguments.
@@ -2013,7 +2058,7 @@ Lambdas. #
canvas.onUpdate = delta_ms => print delta_ms
Lambdas that need a block of statements can be declared with the func
keyword without a name.
--- Assigning lambda block to a variable.
+-- Assigning lambda block to a variable.
var add = func (a, b):
return a + b
@@ -2022,50 +2067,50 @@ Lambdas. #
..func (delta_ms):
print delta_ms
-Passing a lambda block as a call argument is only possible in a call block. Planned Feature See Function calls.
-
-Closures. #
+Passing a lambda block as a call argument is only possible in a call block. Planned Feature See Function calls.
+^topic
+$(htmlContent) #
Lambdas can capture local variables from parent blocks. This example shows the lambda f
capturing a
from the main scope: Incomplete, only variables one parent block away can be captured.
-var a = 1
+var a = 1
var f = func():
return a + 2
print f() -- "3"
The following lambda expression captures a
from the function add
:
-func add():
+func add():
var a = 123
return b => a + b
var addTo = add()
print addTo(10) -- "133"
Like static variables, static functions can not reference local variables outside of their scope:
-var a = 1
+var a = 1
func foo():
print a -- CompileError: Undeclared variable `a`.
-
-Named parameters. #
+^topic
+$(htmlContent) #
Planned Feature
-
-Optional parameters. #
+^topic
+$(htmlContent) #
Planned Feature
-
-Variadic parameters. #
+^topic
+$(htmlContent) #
Planned Feature
-
-Function calls. #
+^topic
+$(htmlContent) #
The straightforward way to call a function is to use parentheses.
-var d = dist(100, 100, 200, 200)
+var d = dist(100, 100, 200, 200)
You can call functions with named parameters.
Planned Feature
-
var d = dist(x0: 10, x1: 20, y0: 30, y1: 40)
+var d = dist(x0: 10, x1: 20, y0: 30, y1: 40)
-
-Shorthand syntax. #
+^topic
+$(htmlContent) #
The shorthand method for calling functions omits parentheses and commas. This only works for functions that accept parameters:
Incomplete: Only the most trivial cases work with the shorthand method. The case with operators being separated by spaces might not end up being implemented.
-
var d = dist 100 100 200 200 -- Calls the function `dist`.
+var d = dist 100 100 200 200 -- Calls the function `dist`.
func random(): -- Function with no parameters.
return 4
@@ -2075,24 +2120,24 @@ Shorthand syntax. #
The top level arguments for the shorthand convention must be separated by whitespace. A string can contain whitespace since it's surrounded by delimiters.
-var a = myFunc 'cyber script'
+var a = myFunc 'cyber script'
The following has a binary expression with spaces inbetween which is not allowed. Removing that whitespace fixes the call expression.
-var a = myFunc 1 + 2 -- Not allowed.
+var a = myFunc 1 + 2 -- Not allowed.
a = myFunc 1+2 -- Correct.
Wrapping arguments in parentheses allows you to keep the whitespace in the sub-expression.
--- This calls the function `myFunc` with 2 arguments.
+-- This calls the function `myFunc` with 2 arguments.
var a = myFunc 'hello' (1 + 2 * 3)
-- Nested function call using the shorthand convention.
a = myFunc 'hello' (otherFunc 1+2 'world')
-
-Call block syntax. #
+^topic
+$(htmlContent) #
The call expression block continues to add arguments from the block's body. If arguments are omitted from the initial call expression they can be added inside using the ..
syntax. Arguments mapped to named parameters have a key value syntax separated by a :
. All other arguments are added into a list and passed as the last argument.
Planned Feature
-
foo(123):
+foo(123):
..func ():
return 123
param3: 123
@@ -2101,63 +2146,63 @@ Call block syntax. #
'hello'
In the example above, the function foo
is called with 4 arguments. The first argument 123
is included in the starting call expression. The second argument is a function value inside the call expression block. The third argument is mapped to the param param3
. Finally, the fourth argument is a list that contains 234
, bar()
, and 'hello'
.
-
-Modules. #
+^topic
+$(htmlContent) #
-- Importing.
-- Exporting.
-- Module URI.
-- Visibility.
-- Builtin modules.
-- builtins.
-
+
Modules have their own namespace and contain accessible static symbols. By default, importing another Cyber script returns a module with its declared symbols.
-Importing. #
+$(htmlContent) #
Import declarations create a local alias to the module referenced by the import specifier. The Cyber CLI comes with some builtin modules like math
and test
. If the specifier does not refer to a builtin module, it looks for a Cyber script file relative to the current script's directory. An embedder can integrate their own module loader and resolver.
-import test
+import test
test.eq(123, 123)
-- Imports are static declarations so they can be anywhere in the script.
@@ -2165,7 +2210,7 @@ Importing. #
print math.cos(0)
When the imported alias needs to be renamed, the import specifier comes after the alias name and must be a string literal.
-import m 'math'
+import m 'math'
print m.random()
-- Loading a Cyber module from the local directory.
@@ -2174,21 +2219,21 @@ Importing. #
print foo.myVar
A Cyber script that is imported doesn't evaluate its main block. Only static declarations are effectively loaded. If there is code in the main block, it will skip evaluation. In the following, only the print
statement in the main.cy
is evaluated.
--- main.cy
+-- main.cy
import a 'foo.cy'
print a.foo
-- foo.cy
import 'bar.cy'
-var Root.foo = 123
+var .foo = 123
print foo -- Statement is ignored.
-- bar.cy
-var Root.bar = 321
+var .bar = 321
print bar -- Statement is ignored.
You can have circular imports in Cyber. In the following example, main.cy
and foo.cy
import each other without any problems.
--- main.cy
+-- main.cy
import foo 'foo.cy'
func printB():
@@ -2205,51 +2250,50 @@ Importing. #
func printC():
print 'done'
-Static variable declarations from imports can have circular references. Read more about this in Static Variables.
+Static variable declarations from imports can have circular references. Read more about this in Static Variables.
Modules can also be destructured using the following syntax:
Planned Feature
-
import { cos, pi } 'math'
+import { cos, pi } 'math'
print cos(pi)
-
-Exporting. #
+^topic
+$(htmlContent) #
All static declarations are exported when the script's module is loaded.
-func foo(): -- Exported static function.
+func foo(): -- Exported static function.
print 123
-var Root.bar = 234 -- Exported static variable.
+var .bar = 234 -- Exported static variable.
-type Thing object: -- Exported type.
+type Thing: -- Exported type.
var a float
-
-Module URI. #
-To get the absolute path of the current module, reference the compile-time variable ModUri
.
+^topic
+$(htmlContent) #
+
To get the absolute path of the current module, reference the compile-time constant #modUri
.
This can be used with os.dirName
to get the current module directory.
-print #ModUri -- Prints '/some/path/foo.cy'
+print #modUri -- Prints '/some/path/foo.cy'
import os
-print os.dirName(#ModUri) -- Prints '/some/path'
+print os.dirName(#modUri) -- Prints '/some/path'
-
-Visibility. #
+^topic
+$(htmlContent) #
The annotation @hide
provides a hint to editors that a static symbol should not appear in the auto-complete. Despite this, the symbol is still reachable.
-
-Builtin modules. #
-Builtin modules are the bare minimum that comes with Cyber. The embeddable library contains these modules and nothing more. They include:
+^topic
+$(htmlContent) #
+Builtin modules are the bare minimum that comes with Cyber. The embeddable library contains these modules and nothing more. They include:
-- builtins: Cyber related functions and commonly used utilities.
-- math: Math constants and functions.
+- builtins: Cyber related functions and commonly used utilities.
+- math: Math constants and functions.
-
-builtins. #
+^topic
+$(htmlContent) #
The builtins
module contains functions related to Cyber and common utilities. It is automatically imported into each script's namespace.
Sample usage:
--- `print` and `typeof` are available without imports.
+-- `print` and `typeof` are available without imports.
print 'hello'
print typeof('my str').id()
-
func copy(val any) any
Copies a primitive value or creates a shallow copy of an object value.
@@ -2267,7 +2311,7 @@ builtins. #
func must(val any) any
If val
is an error, panic(val)
is invoked. Otherwise, val
is returned.
func panic(err any) none
-Stop execution in the current fiber and starts unwinding the call stack. See Unexpected Errors.
+Stop execution in the current fiber and starts unwinding the call stack. See Unexpected Errors.
func parseCyber(src string) Map
Parses Cyber source string into structured map object. Currently, only metadata about static declarations is made available but this will be extended to include an AST.
func parseCyon(src string) any
@@ -2284,15 +2328,18 @@ builtins. #
Returns the value's type as a metatype
object.
func typesym(val any) symbol
Returns the value's type as one of the predefined symbols: .float, .int, .bool, .object, .list, .map, .string, .array, .function, .fiber, .pointer, .symbol, .metatype, .none, .error
-
type bool
#
+^topic
+$(htmlContent) #
func bool.'$call'(val any) bool
Converts a value to either true
or false
.
-
type error
#
+^topic
+$(htmlContent) #
func sym() symbol
Return the underlying symbol
.
func error.'$call'(val any) error
Create an error from an enum or symbol.
-
type int
#
+^topic
+$(htmlContent) #
func $prefix~() int
func $prefix-() int
func $infix<(o any) bool
@@ -2316,7 +2363,8 @@ builtins. #
opts.pad
provides the ASCII rune that is used for padding with a string length of opts.width
.
func int.'$call'(val any) int
Converts a value to an 48-bit integer.
-
type float
#
+^topic
+$(htmlContent) #
func $prefix-() float
func $infix<(o any) bool
func $infix<=(o any) bool
@@ -2330,7 +2378,8 @@ builtins. #
func $infix^(o any) float
func float.'$call'(val any) float
Converts the value to a float
. Panics if type conversion fails.
-
type List
#
+^topic
+$(htmlContent) #
func $index(idx any) any
func $setIndex(idx any, val any) none
func $slice(start any, end any) List
@@ -2353,11 +2402,14 @@ builtins. #
func slice(start any, end any) List
func List.fill(val any, n int) List
Creates a list with initial capacity of n
and values set to val
. If the value is an object, it is shallow copied n
times.
-
type ListIterator
#
+^topic
+$(htmlContent) #
func next() any
-
type tuple
#
+^topic
+$(htmlContent) #
func $index(idx int) any
-
type Map
#
+^topic
+$(htmlContent) #
func $index(key any) any
func $setIndex(key any, val any) none
func remove(key any) none
@@ -2366,9 +2418,11 @@ builtins. #
Returns the number of key-value pairs in the map.
func iterator() MapIterator
Returns a new iterator over the map elements.
-
type MapIterator
#
+^topic
+$(htmlContent) #
func next() any
-
type string
#
+^topic
+$(htmlContent) #
func $infix+(o any) string
func concat(o string) string
Returns a new string that concats this string and str
.
@@ -2412,7 +2466,8 @@ builtins. #
Returns this string in uppercase.
func string.'$call'(val any) string
Converts a value to a string.
-
type array
#
+^topic
+$(htmlContent) #
func $infix+(o any) array
func concat(other array) array
Returns a new array that concats this array and other
.
@@ -2458,8 +2513,10 @@ builtins. #
Returns the array with ends trimmed from runes in delims
. mode
can be .left, .right, or .ends.
func array.'$call'(val any) array
Converts a string to an byte array
.
-
type arrayIterator
#
-type pointer
#
+^topic
+$(htmlContent) #
+^topic
+$(htmlContent) #
func addr() int
Returns the memory address as an int
. The value may be negative since it's bitcasted from an unsigned 48-bit integer but it retains the original pointer bits.
func asObject() any
@@ -2474,23 +2531,26 @@ type pointer
#Unsafe. Returns an array
with a copy of the byte data starting from an offset to the specified length.
func pointer.'$call'(val any) pointer
Converts a int
to a pointer
value, or casts to a pointer
. This is usually used with FFI.
-
type ExternFunc
#
+^topic
+$(htmlContent) #
func addr() int
Returns the memory address as an int
. The value may be negative since it's bitcasted from an unsigned 48-bit integer but it retains the original pointer bits.
-
type Fiber
#
+^topic
+$(htmlContent) #
func status() symbol
-
type metatype
#
+^topic
+$(htmlContent) #
func id() int
-math. #
+^topic
+$(htmlContent) #
The math module contains commonly used math constants and functions.
Sample usage:
-import math
+import math
var r = 10.0
print(math.pi * r^2)
-
var e float
Euler's number and the base of natural logarithms; approximately 2.718.
@@ -2595,23 +2655,23 @@ math. #
func trunc(a float) float
Returns the integer portion of x, removing any fractional digits.
-Std modules. #
+^topic
+$(htmlContent) #
Std modules come with Cyber's CLI. They include:
-- os: System level functions.
-- test: Utilities for testing.
+- os: System level functions.
+- test: Utilities for testing.
-
-os. #
+^topic
+$(htmlContent) #
Cyber's os module contains system level functions. It's still undecided as to how much should be included here so it's incomplete. You can still access os and libc functions yourself using Cyber's FFI or embedding API.
Sample usage:
-import os
+import os
var map = os.getEnvAll()
for map -> [k, v]:
- print '$(k) -> $(v)'
+ print "$(k) -> $(v)"
-
var cpu string
The current cpu arch's tag name.
@@ -2695,7 +2755,8 @@ os. #
Removes an environment variable by key.
func writeFile(path string, contents any) none
Writes contents
as a string or bytes to a file.
-
type File
#
+^topic
+$(htmlContent) #
func close() none
Closes the file handle. File ops invoked afterwards will return error.Closed
.
func iterator() any
@@ -2718,16 +2779,19 @@ os. #
Returns an iterable that streams lines ending in \n
, \r
, \r\n
, or the EOF
. The lines returned include the new line character(s). A buffer size of bufSize
bytes is allocated for reading. If \r
is found at the end of the read buffer, the line is returned instead of waiting to see if the next read has a connecting \n
.
func write(val any) int
Writes a string
or array
at the current file position. The number of bytes written is returned.
-
type Dir
#
+^topic
+$(htmlContent) #
func iterator() DirIterator
Returns a new iterator over the directory entries. If this directory was not opened with the iterable flag, error.NotAllowed
is returned instead.
func stat() Map
Returns info about the file as a Map
.
func walk() DirIterator
Returns a new iterator over the directory recursive entries. If this directory was not opened with the iterable flag, error.NotAllowed
is returned instead.
-
type DirIterator
#
+^topic
+$(htmlContent) #
func next() any
-
type FFI
#
+^topic
+$(htmlContent) #
func bindCallback(fn any, params List, ret symbol) ExternFunc
Creates an ExternFunc
that contains a C function pointer with the given signature. The extern function is a wrapper that calls the provided user function. Once created, the extern function is retained and managed by the FFI context.
func bindLib(path any) any
@@ -2744,102 +2808,107 @@ os. #
Allocates memory for a C struct or primitive with the given C type specifier. A pointer
to the allocated memory is returned. Eventually this will return a cpointer
instead which will be more idiomatic to use.
func unbindObjPtr(obj any) none
Releases the object from the FFI context. External code should no longer use the object's pointer since it's not guaranteed to exist or point to the correct object.
-
type CArray
#
-type CDimArray
#
+^topic
+$(htmlContent) #
+^topic
+$(htmlContent) #
-map DirEntry
#
-key summary 'name' -> array
The name of the file or directory. 'type' -> #file | #dir | #unknown
The type of the entry.
-map DirWalkEntry
#
-key summary 'name' -> array
The name of the file or directory. 'path' -> array
The path of the file or directory relative to the walker's root directory. 'type' -> #file | #dir | #unknown
The type of the entry.
-map ArgOption
#
-key summary 'name' -> string
The name of the option to match excluding the hyphen prefix. eg. -path
'type' -> metatype(string | float | boolean)
Parse as given value type. 'default' -> any
Optional: Default value if option is missing. none
is used if this is not provided.
-test. #
+^topic
+$(htmlContent) #
+key summary 'name' -> array
The name of the file or directory. 'type' -> #file | #dir | #unknown
The type of the entry.
^topic
+$(htmlContent) #
+key summary 'name' -> array
The name of the file or directory. 'path' -> array
The path of the file or directory relative to the walker's root directory. 'type' -> #file | #dir | #unknown
The type of the entry.
^topic
+$(htmlContent) #
+key summary 'name' -> string
The name of the option to match excluding the hyphen prefix. eg. -path
'type' -> metatype(string | float | boolean)
Parse as given value type. 'default' -> any
Optional: Default value if option is missing. none
is used if this is not provided.
^topic
+$(htmlContent) #
The test
module contains utilities for testing.
Sample usage:
-import t 'test'
+import t 'test'
var a = 123 + 321
t.eq(a, 444)
-
-func eq(a any, b any) any
+func assert(pred any) none
+Panics if pred
is false
.
+
func eq(a any, b any) bool
Returns whether two values are equal. Panics with error.AssertError
if types or values do not match up.
-
func eqList(a any, b any) any
-Returns true if two lists have the same size and the elements are equal as if eq
was called on those corresponding elements.
-
func eqNear(a any, b any) any
-Returns two numbers are near each other within epsilon 1e-5.
+
func eqList(a any, b any) bool
+Returns true
if two lists have the same size and the elements are equal as if eq
was called on those corresponding elements.
+
func eqNear(a any, b any) bool
+Returns true
if two numbers are near each other within epsilon 1e-5.
func fail() any
-FFI. #
+^topic
+$(htmlContent) #
-- FFI context.
-- Declare functions.
-- Bind library.
-- Search path.
-- Configuration.
-- Finalizer.
+- FFI context.
+- Declare functions.
+- Bind library.
-- Mappings.
-- Bind to Cyber type.
-- Pointers.
-- cbindgen.cy
+- Mappings.
+- Bind to Cyber type.
+- Pointers.
+- cbindgen.cy
-
+
Cyber supports binding to an existing C ABI compatible library at runtime.
This allows you to call into dynamic libraries created in C or other languages.
Cyber uses libtcc
to JIT compile the bindings so function calls are fast.
-The example shown below can be found in Examples.
-FFI context. #
+The example shown below can be found in Examples.
+$(htmlContent) #
An FFI context contains declarations that map C to Cyber. Afterwards, it allows you to bind to a dynamic library or create interoperable objects. To create a new FFI
context:
-import os
+import os
var ffi = os.newFFI()
-
-Declare functions. #
+^topic
+$(htmlContent) #
Functions from a library are first declared using cfunc
which accepts C types in the form of symbols. In a future update they will accept C syntax instead.
-ffi.cfunc('add', [.int, .int], .int)
+ffi.cfunc('add', [.int, .int], .int)
The first argument refers to the symbol's name in the dynamic library.
The second argument contains the function's parameter types and finally the last argument is the function's return type.
The example above maps to this C function:
-int add(int a, int b) {
+int add(int a, int b) {
return a + b;
}
-
-Bind library. #
+^topic
+$(htmlContent) #
bindLib
accepts the path to the library and returns a object which can be used to invoke the functions declared from cfunc
:
-my lib = ffi.bindLib('./mylib.so')
+my lib = ffi.bindLib('./mylib.so')
lib.add(123, 321)
Note that my
is used to allow lib
to be used dynamically since the type is unknown at compile-time.
-
-Search path. #
+^topic
+$(htmlContent) #
If the path argument to bindLib
is just a filename, the search steps for the library is specific to the operating system. Provide an absolute (eg. '/foo/mylib.so') or relative (eg. './mylib.so') path to load from a direct location instead. When the path argument is none
, it loads the currently running executable as a library allowing you to bind exported functions from the Cyber CLI or your own application/runtime.
-
-Configuration. #
+^topic
+$(htmlContent) #
By default bindLib
returns an anonymous object with the binded C-functions as methods. This is convenient for invoking functions using the method call syntax. If a config is passed into bindLib
as the second argument, genMap: true
makes bindLib
return a map instead with the binded C-functions as Cyber functions.
-
-Finalizer. #
+^topic
+$(htmlContent) #
The resulting object of bindLib
holds a reference to an internal TCCState which owns the loaded JIT code.
Once the object is released by ARC, the TCCState is also released which removes the JIT code from memory.
-
-Mappings. #
-When using cfunc
or cbind
declarations, symbols are used to represent default type mappings from Cyber to C and back:
+^topic
+$(htmlContent) #
+When using cfunc
or cbind
declarations, symbols are used to represent default type mappings from Cyber to C and back:
Incomplete: This is not the final API for dynamically loading and interfacing with C libraries. The plan is to parse a subset of C headers to bind to Cyber types and functions.
-
Binding Cyber C .bool bool bool .char int int8_t, signed char .uchar int uint8_t, unsigned char .short int int16_t, short .ushort int uint16_t, unsigned short .int int int32_t, int .uint int uint32_t, unsigned int .long int int64_t, long long .ulong int uint64_t, unsigned long long .usize int size_t, uintptr_t .float float float .double float double (1) .charPtr pointer char* .voidPtr pointer void* (2) type {S} object type {S} object struct
+
Binding Cyber C .bool bool bool .char int int8_t, signed char .uchar int uint8_t, unsigned char .short int int16_t, short .ushort int uint16_t, unsigned short .int int int32_t, int .uint int uint32_t, unsigned int .long int int64_t, long long .ulong int uint64_t, unsigned long long .usize int size_t, uintptr_t .float float float .double float double (1) .charPtr pointer char* .voidPtr pointer void* (2) type {S} type {S} struct
- Use
os.cstr()
and pointer.fromCstr()
to convert between a Cyber string and a null terminated C string.
- The mapping from a Cyber object type
S
and the C-struct can be declared with cbind
.
-
-Bind to Cyber type. #
+^topic
+$(htmlContent) #
cbind
is used to bind a C struct to a Cyber object type. Once declared, the Cyber type can be used as a binding type in function declarations:
-import os
+import os
-type MyObject object:
+type MyObject:
var a float
var b pointer
var c bool
@@ -2851,7 +2920,7 @@ Bind to Cyber type. #<
var res = lib.foo([MyObject a: 123.0, b: os.cstr('foo'), c: true])
The example above maps to these C declarations in mylib.so
:
-typedef struct MyObject {
+typedef struct MyObject {
double a;
char* b;
bool c;
@@ -2862,82 +2931,82 @@ Bind to Cyber type. #<
}
cbind
also generates ptrTo[Type]
as a helper function to dereference an opaque ptr to a new Cyber object:
-ffi.cfunc('foo', [MyObject], .voidPtr)
+ffi.cfunc('foo', [MyObject], .voidPtr)
my lib = ffi.bindLib('./mylib.so')
var ptr = lib.foo([MyObject a: 123, b: os.cstr('foo'), c: true])
var res = lib.ptrToMyObject(ptr)
-
-Pointers. #
-A pointer
is used to read or write to an exact memory address. This is typically used for FFI to manually map Cyber types to C, and back. See type pointer
.
+^topic
+$(htmlContent) #
+A pointer
is used to read or write to an exact memory address. This is typically used for FFI to manually map Cyber types to C, and back. See type pointer
.
A new pointer can be created with the builtin pointer
.
-var ptr = pointer(0xDEADBEEF)
+var ptr = pointer(0xDEADBEEF)
print ptr.value() --'3735928559'
-
-cbindgen.cy #
-cbindgen.cy is a Cyber script that automatically generates bindings given a C header file. Some example bindings that were generated include: Raylib and LLVM.
-
-Error Handling. #
+^topic
+$(htmlContent) #
+cbindgen.cy is a Cyber script that automatically generates bindings given a C header file. Some example bindings that were generated include: Raylib and LLVM.
+^topic
+$(htmlContent) #
-
+
Cyber provides a throw/catch mechanism to handle expected errors. For unexpected errors, panics can be used as a fail-fast mechanism to abort the currently running fiber.
-Error trait. #
+$(htmlContent) #
Only types that implement the Error
trait can be thrown or attached to a panic.
Since the Error
trait is empty, it's simple to turn any type into a throwable type.
-
-error
value. #
+^topic
+$(htmlContent) #
An error
value contains a symbol
and implements the Error
trait. They can be created without a declaration using the error literal:
-var err = error.Oops
+var err = error.Oops
Use sym()
to obtain the underlying symbol:
-print err.sym() -- Prints ".Oops"
+print err.sym() -- Prints ".Oops"
Since error
is a primitive value, it can be compared using the ==
operator.
-if err == error.Oops:
+if err == error.Oops:
handleOops()
-- Alternatively.
if err.sym() == .Oops:
handleOops()
-
-Enum error. #
+^topic
+$(htmlContent) #
By implementing the Error
trait, an enum type can be throwable: Planned Feature
-type MyError enum:
+type MyError enum:
with Error
boom
badArgument
@@ -2945,11 +3014,11 @@ Enum error. #
var err = MyError.nameTooLong
-
-Throwing errors. #
+^topic
+$(htmlContent) #
Use the throw
keyword to throw errors.
A thrown error continues to bubble up the call stack until it is caught by a try
block or expression.
-func fail():
+func fail():
throw error.Oops -- Throws an error with the symbol `#Oops`
func fail2():
@@ -2957,30 +3026,31 @@ Throwing errors. #
-- that implement the `Error` trait.
throw
can also be used as an expression.
-func fail():
+func fail():
var a = false or throw error.False
-
-Catching errors. #
-try
block. #
+^topic
+$(htmlContent) #
+^topic
+$(htmlContent) #
The try
block catches thrown errors and resumes execution in a followup catch
block:
-try:
+try:
funcThatCanFail()
catch err:
print err -- 'error.Failed'
-
-caught
variable. #
+^topic
+$(htmlContent) #
The contextual caught
variable is used to reference the caught error: Planned Feature
-try:
+try:
funcThatCanFail()
catch:
print caught -- 'error.Failed'
-
-catch
matching. #
+^topic
+$(htmlContent) #
An inner catch
block contains a matching clause: Planned Feature
-try:
+try:
funcThatCanFail()
catch error.BadDay:
eatSnack()
@@ -2988,36 +3058,37 @@ catch
matching. #
print caught
Enum errors can be matched: Planned Feature
-try:
+try:
funcThatCanFail()
catch MyError.Boom:
print 'Kaboom!'
catch:
print caught
-
-try
expression. #
+^topic
+$(htmlContent) #
The try
expression either returns a non-error result or the default value from the catch
clause:
-var res = try funcThatCanFail() catch 123
+var res = try funcThatCanFail() catch 123
print res -- '123'
Since errors bubble up automatically, any errors thrown from sub-expressions are also caught:
-var res = try happyFunc(funcThatCanFail()) catch 123
+var res = try happyFunc(funcThatCanFail()) catch 123
print res -- '123'
-
-Value or error. #
+^topic
+$(htmlContent) #
When the catch
clause is omitted, the try
expression will return either the value or the error:
-var res = try funcThatCanFail()
+