diff --git a/index.html b/index.html index 0ff1acdd7..2979ab15f 100644 --- a/index.html +++ b/index.html @@ -998,7 +998,7 @@

Cyber Docs

-
v0.4-dev 12-2e4d5c1
+
v0.4-dev 20-d9f355d
-

Introduction. #

-

Cyber is a fast, efficient, and concurrent scripting language. The landing page is at cyberscript.dev and contains performance metrics and release notes.

+$(htmlContent) # +

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) #
-

top

+

^top

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'
 
-

parent

-

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
 
-

parent

-

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.

-

parent

-

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
 
-

parent

-

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.

-

parent

-

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"
-

parent

-

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.

-

parent

-

Reserved identifiers. #

-

Keywords. #

+^topic +$(htmlContent) # +^topic +$(htmlContent) #

There are 25 general keywords. This list categorizes them:

-

parent

-

Contextual keywords. #

+^topic +$(htmlContent) #

These keywords only have meaning in a certain context.

-

parent

-

Symbols. #

+^topic +$(htmlContent) # -

parent

-

Literals. #

- -

parent

-

Operators. #

+^topic +$(htmlContent) #

Cyber supports the following operators. They are ordered from highest to lowest precedence.

-
OperatorDescription
<< >>Bitwise left shift, right shift.
&Bitwise and.
\| \|\|Bitwise or, exclusive or.
^Power.
/ % *Division, modulus, multiplication.
+ -Addition, subtraction.
asType casting.
> >= < <= != ==Greater, greater or equal, less, less or equal, not equals, equals.
andLogical and.
orLogical or.

parent

-

Arithmetic Operators. #

-

The following arithmetic operators are supported for the numeric data types.

-
1 + 2     -- Addition, evaluates to 3.
+
OperatorDescription
<< >>Bitwise left shift, right shift.
&Bitwise and.
| ||Bitwise or, exclusive or.
^Power.
/ % *Division, modulus, multiplication.
+ -Addition, subtraction.
asType casting.
> >= < <= != ==Greater, greater or equal, less, less or equal, not equals, equals.
andLogical and.
orLogical 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
 
-

parent

-

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
 
-

parent

-

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

-

parent

-

Operator overloading. #

-

See Operator overloading in Metaprogramming.

-

parent

-

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.

-

parent

-

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. #

], ]
-

parent

-

Data Types. #

+^topic +$(htmlContent) #
-

top

+

^top

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.

-

parent

-

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.
  • -

    parent

    -

    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.

    -

    parent

    -

    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) 
     
    -

    parent

    -

    Big Numbers. #

    +^topic +$(htmlContent) #

    Planned Feature

    -

    parent

    -

    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 SequenceCodeDescription
    \a0x07Terminal bell.
    \b0x08Backspace.
    \e0x1bEscape character.
    \n0x0aLine feed character.
    \r0x0dCarriage return character.
    \t0x09Horizontal 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 SequenceCodeDescription
    \a0x07Terminal bell.
    \b0x08Backspace.
    \e0x1bEscape character.
    \n0x0aLine feed character.
    \r0x0dCarriage return character.
    \t0x09Horizontal 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"
    -

    parent

    -

    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.

    -

    parent

    -

    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))"
     
    -

    parent

    -

    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"
     
    -

    parent

    -

    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]
     
    -

    parent

    -

    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)
    -

    parent

    -

    Tuples. #

    -

    Incomplete: Tuples can only be created from @host funcs at the moment.

    -

    parent

    -

    Maps. #

    -

    Maps are a builtin type that store key value pairs in dictionaries. See type Map.

    -

    parent

    -

    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,
     ]
     
    -

    parent

    -

    Empty map. #

    +^topic +$(htmlContent) #

    The empty map is initialized using [:]:

    -
    var empty = [:]
    +
    var empty = [:]
     
    -

    parent

    -

    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
     
    -

    parent

    -

    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)"
    -

    parent

    -

    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
    -

    parent

    -

    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.

    -

    parent

    -

    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.

    -

    parent

    -

    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"
     
    -

    parent

    -

    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
     
    -

    parent

    -

    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
     
    -

    parent

    -

    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()
    -

    parent

    -

    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"
     
    -

    parent

    -

    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'
     
    -

    parent

    -

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

    parent

    -

    Control Flow. #

    +^topic +$(htmlContent) #
    -

    top

    +

    ^top

    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. #

    -

    parent

    -

    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'
     
    -

    parent

    -

    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'
     
    -

    parent

    -

    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
     
    -

    parent

    -

    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
     
    -

    parent

    -

    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
     
    -

    parent

    -

    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
     
    -

    parent

    -

    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)"
     
    -

    parent

    -

    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)"
     
    -

    parent

    -

    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
     
    -

    parent

    -

    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
     
    -

    parent

    -

    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.

    -

    parent

    -

    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}.

    -

    parent

    -

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

    parent

    -

    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.

    -

    parent

    -

    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

    -

    parent

    -

    Functions. #

    +^topic +$(htmlContent) #
      -
    • Static functions.
    • -
    • Function overloading.
    • -
    • Lambdas.
    • -
    • Closures.
    • -
    • Named parameters.
    • -
    • Optional parameters.
    • -
    • Variadic parameters.
    • -
    • Function calls. -

      top

      +

      ^top

      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)
       
      -

      parent

      -

      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.

      -

      parent

      -

      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.

      -

      parent

      -

      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`.
       
      -

      parent

      -

      Named parameters. #

      +^topic +$(htmlContent) #

      Planned Feature

      -

      parent

      -

      Optional parameters. #

      +^topic +$(htmlContent) #

      Planned Feature

      -

      parent

      -

      Variadic parameters. #

      +^topic +$(htmlContent) #

      Planned Feature

      -

      parent

      -

      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)
       
      -

      parent

      -

      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')
       
      -

      parent

      -

      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'.

      -

      parent

      -

      Modules. #

      +^topic +$(htmlContent) #
      -

      top

      +

      ^top

      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)
       
      -

      parent

      -

      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
       
      -

      parent

      -

      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'
       
      -

      parent

      -

      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.

      -

      parent

      -

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

      parent

      -

      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()
       
      -

      parent

      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)
       
      -

      parent

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

      parent

      -

      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)"
       
      -

      parent

      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 #

      -
      keysummary
      'name' -> arrayThe name of the file or directory.
      'type' -> #file | #dir | #unknownThe type of the entry.

      parent

      -

      map DirWalkEntry #

      -
      keysummary
      'name' -> arrayThe name of the file or directory.
      'path' -> arrayThe path of the file or directory relative to the walker's root directory.
      'type' -> #file | #dir | #unknownThe type of the entry.

      parent

      -

      map ArgOption #

      -
      keysummary
      'name' -> stringThe name of the option to match excluding the hyphen prefix. eg. -path
      'type' -> metatype(string | float | boolean)Parse as given value type.
      'default' -> anyOptional: Default value if option is missing. none is used if this is not provided.

      parent

      -

      test. #

      +^topic +$(htmlContent) # +
      keysummary
      'name' -> arrayThe name of the file or directory.
      'type' -> #file | #dir | #unknownThe type of the entry.
      ^topic +$(htmlContent) # +
      keysummary
      'name' -> arrayThe name of the file or directory.
      'path' -> arrayThe path of the file or directory relative to the walker's root directory.
      'type' -> #file | #dir | #unknownThe type of the entry.
      ^topic +$(htmlContent) # +
      keysummary
      'name' -> stringThe name of the option to match excluding the hyphen prefix. eg. -path
      'type' -> metatype(string | float | boolean)Parse as given value type.
      'default' -> anyOptional: 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)
       
      -

      parent

      -

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

        top

        +

        ^top

        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()
         
        -

        parent

        -

        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;
         }
         
        -

        parent

        -

        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.

        -

        parent

        -

        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.

        -

        parent

        -

        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.

        -

        parent

        -

        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.

        -

        parent

        -

        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.

        -
        BindingCyberC
        .boolboolbool
        .charintint8_t, signed char
        .ucharintuint8_t, unsigned char
        .shortintint16_t, short
        .ushortintuint16_t, unsigned short
        .intintint32_t, int
        .uintintuint32_t, unsigned int
        .longintint64_t, long long
        .ulongintuint64_t, unsigned long long
        .usizeintsize_t, uintptr_t
        .floatfloatfloat
        .doublefloatdouble
        (1) .charPtrpointerchar*
        .voidPtrpointervoid*
        (2) type {S} objecttype {S} objectstruct
          +
      BindingCyberC
      .boolboolbool
      .charintint8_t, signed char
      .ucharintuint8_t, unsigned char
      .shortintint16_t, short
      .ushortintuint16_t, unsigned short
      .intintint32_t, int
      .uintintuint32_t, unsigned int
      .longintint64_t, long long
      .ulongintuint64_t, unsigned long long
      .usizeintsize_t, uintptr_t
      .floatfloatfloat
      .doublefloatdouble
      (1) .charPtrpointerchar*
      .voidPtrpointervoid*
      (2) type {S}type {S}struct
      1. Use os.cstr() and pointer.fromCstr() to convert between a Cyber string and a null terminated C string.
      2. The mapping from a Cyber object type S and the C-struct can be declared with cbind.
      -

      parent

      -

      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)
       
      -

      parent

      -

      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'
       
      -

      parent

      -

      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.

      -

      parent

      -

      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) #
      -

      top

      +

      ^top

      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.

      -

      parent

      -

      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()
       
      -

      parent

      -

      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
      -

      parent

      -

      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
       
      -

      parent

      -

      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'
       
      -

      parent

      -

      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'
       
      -

      parent

      -

      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
       
      -

      parent

      -

      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'
       
      -

      parent

      -

      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()
      +
      var res = try funcThatCanFail()
       if res == error.Failed:
           print 'Result is an error.'
       
      -

      parent

      -

      Semantic checks. #

      -

      throws specifier. #

      +^topic +$(htmlContent) # +^topic +$(htmlContent) #

      The throws specifier indicates that a function contains a throwing expression that was not caught with try catch.

      When a function does not have a return specifier, it's implicitly given the throws specifier:

      -
      func foo():
      +
      func foo():
           throw error.Failure
       
       func bar() throws:
      @@ -3026,25 +3097,25 @@ 

      throws specifier. func result(cond bool) throws, int: +
      func result(cond bool) throws, int:
           if cond:
               return 123
           else:
               throw error.Failure
       
      -

      parent

      -

      Requiring throws. #

      +^topic +$(htmlContent) #

      A compile-time error is issued when a typed function without a throws specifier contains an uncaught throwing expression: Planned Feature

      -
      func foo(a int) int:
      +
      func foo(a int) int:
           if a == 10:
               throw error.Failure -- CompileError. `foo` requires the `throws`
           else:                   -- specifier or any throwing expression must
               return a * 2        -- be caught with `try catch`.
       
      -

      parent

      -

      Stack trace. #

      +^topic +$(htmlContent) #

      When an uncaught error bubbles up to the top, its stack trace from the throw callsite is dumped to the console. The builtin errorTrace() and errorReport() are used to obtain the stack trace info.

      -
      try:
      +
      try:
           funcThatCanFail()
       catch:
           -- Prints the stack trace summary of the caught error.
      @@ -3054,43 +3125,43 @@ 

      Stack trace. #

      var info = errorTrace() print info.frames.len()
      -

      parent

      -

      Unexpected errors. #

      +^topic +$(htmlContent) #

      An unexpected error is an error that is not meant to be handled at runtime.

      -

      parent

      -

      Panics. #

      +^topic +$(htmlContent) #

      The builtin panic is used as a fail-fast mechanism to quickly exit the current fiber with an error payload:

      -
      func kaboom():
      +
      func kaboom():
           panic(error.danger)
       
       kaboom()     -- Script ends and prints the stack trace.
       

      Panics can not be caught using try catch. Once panic is invoked, the current fiber stops execution and begins to unwind its call stack. Once the error is propagated to the root, the fiber ends and transitions to a panic state. If the main fiber ends this way, the VM begins to shutdown. Otherwise, execution resumes on the next fiber which allows recovery from a panic.

      -

      parent

      -

      Concurrency. #

      +^topic +$(htmlContent) #
        -
      • Fibers. -

        top

        +

        ^top

        Cyber supports fibers as a concurrency mechanism. There are plans to support preemptive concurrency with async/await as well as multithreading.

        -

        Fibers. #

        +$(htmlContent) #

        A fiber represents a separate execution context as a first-class value. It contains it's own call stack and program counter. Fibers by themselves do not enable parallelism.

        -

        parent

        -

        Creating fibers. #

        +^topic +$(htmlContent) #

        The coinit keyword creates and returns a new fiber using a function as the entry point:

        -
        var count = 0
        +
        var count = 0
         
         var foo = func ():
             count += 1
        @@ -3107,10 +3178,10 @@ 

        Creating fibers. #

        A fiber does not start execution until coresume is invoked on it. coyield pauses the current fiber and execution is returned to the previous fiber that invoked coresume.

        -

        parent

        -

        Passing arguments. #

        +^topic +$(htmlContent) #

        Arguments after the callee are passed into the entry function:

        -
        var count = 0
        +
        var count = 0
         
         var increment = func (inc):
             count += inc
        @@ -3120,11 +3191,11 @@ 

        Passing arguments. # print count -- '5'

        When the fiber is created, the arguments are saved inside the fiber's stack. Once the first coresume is invoked, the entry function is invoked with the saved arguments.

        -

        parent

        -

        Reset state. #

        +^topic +$(htmlContent) #

        To reset a fiber to its initial state, invoke reset(). Planned Feature When reset, the existing stack is unwinded, the program counter returns to the starting point, and the state is set to .init:

        -
        func fib(n int) int:
        +
        func fib(n int) int:
             coyield n
             if n < 2:
                 return n
        @@ -3141,11 +3212,11 @@ 

        Reset state. #

        fiber.reset() print(coresume task) -- Prints "10"
        -

        parent

        -

        Rebinding arguments. #

        +^topic +$(htmlContent) #

        Arguments attached to the fiber can be rebinded with a different set of values. Planned Feature This allows fiber reuse, instead of creating a new fiber:

        -
        var task = coinit(fib, 10)
        +
        var task = coinit(fib, 10)
         
         -- Run task to completion.
         var res = 0
        @@ -3158,10 +3229,10 @@ 

        Rebinding arguments.

        -

        parent

        -

        Fiber block. #

        +^topic +$(htmlContent) #

        A fiber block is used to construct a fiber without an entry function. Planned Feature The counting example can be rewritten to:

        -
        var count = 0
        +
        var count = 0
         
         var fiber = coinit:
             count += 1       -- `count is captured`
        @@ -3175,10 +3246,10 @@ 

        Fiber block. #

        print count -- '2'

        Referencing parent variables from the fiber block automatically captures them just like a function closure.

        -

        parent

        -

        Pause and resume. #

        +^topic +$(htmlContent) #

        coyield can be used anywhere in a fiber's call stack to pause execution and return to the previous fiber.

        -
        func foo():
        +
        func foo():
             print 'foo'
             bar()
         
        @@ -3191,17 +3262,17 @@ 

        Pause and resume. #

        coresume also returns the resulting value.

        -
        func foo():
        +
        func foo():
             return 123
         
         var fiber = coinit(foo)
         print(coresume fiber)    -- '123'
         

        coyield can return a value back to coresume. Planned Feature

        -

        parent

        -

        Fiber state. #

        +^topic +$(htmlContent) #

        Use Fiber.status() to get the current state of the fiber.

        -
        func foo():
        +
        func foo():
             coyield
             print 'done'
         
        @@ -3213,62 +3284,62 @@ 

        Fiber state. #

        print fiber.status() -- '.done'

        The main execution context is a fiber as well. Once the main fiber has finished, the VM is done and control is returned to the host.

        -

        parent

        -

        Gas mileage. #

        +^topic +$(htmlContent) #

        Planned Feature

        -

        parent

        -

        Async. #

        +^topic +$(htmlContent) #

        Planned Feature

        -

        parent

        -

        Multi-thread. #

        +^topic +$(htmlContent) #

        Planned Feature

        -

        parent

        -

        Type System. #

        +^topic +$(htmlContent) #
        -

        top

        +

        ^top

        Cyber supports the use of both dynamically and statically typed code.

        -

        Dynamic typing. #

        +$(htmlContent) #

        Dynamic typing can reduce the amount of friction when writing code, but it can also result in more runtime errors.

        -

        parent

        -

        my declaration. #

        +^topic +$(htmlContent) #

        Variables declared with my are assigned the dynamic type:

        -
        my a = 123
        +
        my a = 123
         
        -

        parent

        -

        dynamic vs any #

        -

        dynamic values can be freely used and copied without any compile errors (if there is a chance it can succeed at runtime, see Recent type inference):

        -
        my a = 123
        +^topic
        +$(htmlContent) #
        +

        dynamic values can be freely used and copied without any compile errors (if there is a chance it can succeed at runtime, see Recent type inference):

        +
        my a = 123
         
         func getFirstRune(s string):
             return s[0]
        @@ -3277,7 +3348,7 @@ 

        dynamic vs any var a any = 123 +
        var a any = 123
         
         func getFirstRune(s string):
             return s[0]
        @@ -3287,17 +3358,17 @@ 

        dynamic vs any parent

        -

        Invoking dynamic values. #

        +^topic +$(htmlContent) #

        When a dynamic value is invoked, checks on whether the callee is a function is deferred to runtime.

        -
        my op = 123
        +
        my op = 123
         print op(1, 2, 3)      -- RuntimeError. Expected a function.
         
        -

        parent

        -

        Dynamic return value. #

        +^topic +$(htmlContent) #

        When the return type of a function is not specified, it defaults to the dynamic type. This allows copying the return value to a typed destination without casting:

        -
        func getValue():
        +
        func getValue():
             return 123
         
         func add(a int, b int):
        @@ -3306,16 +3377,16 @@ 

        Dynamic return value.

        The add function defers type checking of getValue() to runtime because it has the dynamic type.

        -

        parent

        -

        Recent type inference. #

        +^topic +$(htmlContent) #

        Although a dynamic variable has the most flexibility, in some situations it is advantageous to know what type it could be.

        The compiler keeps a running record of a dynamic variable's most recent type to gain additional compile-time features without sacrificing flexibility. It can prevent inevitable runtime errors and avoid unnecessary type casts.

        When a dynamic variable is first initialized, it has a recent type inferred from its initializer. In the following, a has the recent type of int at compile-time because numeric literals default to the int type:

        -
        my a = 123
        +
        my a = 123
         

        The recent type can change at compile-time from another assignment. If a is then assigned to a string literal, a from that point on has the recent type of string at compile-time:

        -
        my a = 123
        +
        my a = 123
         foo(a)           -- Valid call expression.
         a = 'hello'
         foo(a)           -- CompileError. Expected `int` argument, got `string`.
        @@ -3325,7 +3396,7 @@ 

        Recent type inference. my a = 123 +
        my a = 123
         if a > 20:
             a = 'hello'
             foo(a)       -- Valid call expression. `foo` can be called without type casting.
        @@ -3335,100 +3406,100 @@ 

        Recent type inference. parent

        -

        Static typing. #

        +^topic +$(htmlContent) #

        Static typing can be incrementally applied which provides compile-time guarantees and prevents runtime errors. Static typing also makes it easier to maintain and refactor your code.

        -

        parent

        -

        Builtin types. #

        +^topic +$(htmlContent) #

        The following builtin types are available in every module: bool, float, int, string, List, Map, error, fiber, any.

        -

        parent

        -

        var declaration. #

        +^topic +$(htmlContent) #

        A var declaration automatically infers the type from the initializer:

        -
        -- Initialized as an `int` variable.
        +
        -- Initialized as an `int` variable.
         var a = 123
         

        var declarations are strictly for static typing. If the assigned value's type is dynamic, the variable's type becomes any.

        -
        func getValue():
        +
        func getValue():
             return ['a', 'list']
         
         -- Initialized as an `any` variable.
         var a = getValue()
         
        -

        parent

        -

        Typed variables. #

        +^topic +$(htmlContent) #

        A typed local variable can be declared by attaching a type specifier after its name. The value assigned to the variable must satisfy the type constraint or a compile error is issued.

        -
        var a float = 123
        +
        var a float = 123
         
         var b int = 123.0    -- CompileError. Expected `int`, got `float`.
         

        Any operation afterwards that violates the type constraint of the variable will result in a compile error.

        -
        a = 'hello'          -- CompileError. Expected `float`, got `string`.
        +
        a = 'hello'          -- CompileError. Expected `float`, got `string`.
         

        Static variables are declared in a similar way:

        -
        var Root.global Map = [:]
        +
        var .global Map = [:]
         

        Unlike local variables, static variable declarations do not infer the type from the right hand side. A specific type must be specified or it will default to the any type.

        -

        parent

        -

        Object types. #

        -

        A type object declaration creates a new object type. Field types are optional and declared with a type specifier after their name.

        -
        type Student object:    -- Creates a new type named `Student`
        +^topic
        +$(htmlContent) #
        +

        A type declaration creates a new object type. Field types are optional and declared with a type specifier after their name.

        +
        type Student:    -- Creates a new type named `Student`
             var name string
             var age  int
             var gpa  float
         
        -

        Instantiating a new object does not require typed fields to be initialized. Missing field values will default to their zero value:

        -
        var s = [Student:]
        +

        Instantiating a new object does not require typed fields to be initialized. Missing field values will default to their zero value:

        +
        var s = [Student:]
         print s.name       -- Prints ""
         print s.age        -- Prints "0"
         print s.gpa        -- Prints "0.0"
         

        Circular type dependencies are allowed if the object can be initialized:

        Planned Feature: Optional types are not currently supported.

        -
        type Node object:
        +
        type Node:
             var val  any
             var next Node?     -- Valid type specifier.
         

        In this example, next has an optional Node? type so it can be initialized to none when creating a new Node object.

        The following example will fail because this version of Node can not be initialized:

        -
        type Node object:
        +
        type Node:
             var val  any
             var next Node
         
         var n = [Node:]    -- CompileError. Can not zero initialize `next`
                            -- because of circular dependency.
         
        -

        parent

        -

        Zero values. #

        +^topic +$(htmlContent) #

        The following shows the zero values of builtin or created types.

        -
        TypeZero value
        booleanfalse
        int0
        float0.0
        string''
        arrayarray('')
        List[]
        Map[:]
        type S object[S:]
        @host type S objectS.$zero()
        dynamicnone
        anynone
        S?none

        parent

        -

        Type aliases. #

        +
        TypeZero value
        booleanfalse
        int0
        float0.0
        string''
        arrayarray('')
        List[]
        Map[:]
        type S[S:]
        #host type SS.$zero()
        dynamicnone
        anynone
        S?none
        ^topic +$(htmlContent) #

        A type alias is declared from a single line type statement. This creates a new type symbol for an existing data type.

        -
        import util './util.cy'
        +
        import util './util.cy'
         
         type Vec3 util.Vec3
         
         var v = [Vec3 x: 3, y: 4, z: 5]
         
        -

        parent

        -

        Functions. #

        +^topic +$(htmlContent) #

        Function parameter and return type specifiers follows a similiar syntax.

        -
        func mul(a float, b float) float:
        +
        func mul(a float, b float) float:
             return a * b
         
         print mul(3, 4)
         print mul(3, '4')  -- CompileError. Function signature mismatch.
         
        -

        parent

        -

        Traits. #

        +^topic +$(htmlContent) #

        Planned Feature

        -

        parent

        -

        Union types. #

        +^topic +$(htmlContent) #

        Planned Feature

        -

        parent

        -

        any type. #

        +^topic +$(htmlContent) #

        A variable with the any type can hold any value, but copying it to narrowed type destination will result in a compile error:

        -
        func square(i int):
        +
        func square(i int):
             return i * i
         
         var a any = 123
        @@ -3438,13 +3509,13 @@ 

        any type. #

        print square(a) -- CompileError. Expected `int`, got `any`.

        a must be explicitly casted to satisfy the type constraint:

        -
        print square(a as int)    -- Prints "100".
        +
        print square(a as int)    -- Prints "100".
         
        -

        parent

        -

        Invoking any values. #

        +^topic +$(htmlContent) #

        Since any is a static type, invoking an any value must be explicitly casted to the appropriate function type.

        Planned Feature: Casting to a function type is not currently supported.

        -
        func add(a int, b int) int:
        +
        func add(a int, b int) int:
             return a + b
         
         var op any = add
        @@ -3453,54 +3524,54 @@ 

        Invoking any values.

        -

        parent

        -

        Type casting. #

        +^topic +$(htmlContent) #

        The as keyword can be used to cast a value to a specific type. Casting lets the compiler know what the expected type is and does not perform any conversions.

        If the compiler knows the cast will always fail at runtime, a compile error is returned instead.

        -
        print('123' as int)       -- CompileError. Can not cast `string` to `int`.
        +
        print('123' as int)       -- CompileError. Can not cast `string` to `int`.
         

        If the cast fails at runtime, a panic is returned.

        -
        var erased any = 123
        +
        var erased any = 123
         add(1, erased as int)     -- Success.
         print(erased as string)   -- Panic. Can not cast `int` to `string`.
         
         func add(a int, b int):
             return a + b
         
        -

        parent

        -

        Metaprogramming. #

        +^topic +$(htmlContent) #
        -

        top

        -

        Operator overloading. #

        +

        ^top

        +$(htmlContent) #

        All operators are implemented as object methods.

        Incomplete: Not all operators have transitioned to the method paradigm.

        Normally this would impact performance, but Cyber generates specialized bytecode for builtin types like int and float. The VM performs inline caching at runtime to eliminate the overhead of evaluating on dynamic operands.

        -

        To overload an operator for an object type, declare $prefix, $infix, $postfix methods. See the available builtin operators. Since operator names aren't allowed as standard identifiers, they are contained in a string literal.

        -
        type Vec2 object:
        +

        To overload an operator for an object type, declare $prefix, $infix, $postfix methods. See the available builtin operators. Since operator names aren't allowed as standard identifiers, they are contained in a string literal.

        +
        type Vec2:
             var x float
             var y float
         
        @@ -3518,7 +3589,7 @@ 

        Operator overloading. type MyCollection object: +
        type MyCollection:
             var arr List
         
             func '$index'(idx):
        @@ -3530,18 +3601,19 @@ 

        Operator overloading. parent

        -

        Builtin operators. #

        +^topic +$(htmlContent) #

        A list of all supported operators:

        -
        OperatorName
        Bitwise not$prefix~
        Minus$prefix-
        Greater$infix>
        Greater equal$infix>=
        Less$infix<
        Less equal$infix<=
        Add$infix+
        Subtract$infix-
        Multiply$infix*
        Divide$infix/
        Modulus$infix%
        Power$infix^
        Bitwise and$infix&
        Bitwise or$infix\|
        Bitwise xor$infix\|\|
        Bitwise left shift$infix<<
        Bitwise right shift$infix>>
        Index$index
        Set index$setIndex
        Slice$slice

        parent

        -

        Custom operators. #

        +
        OperatorName
        Bitwise not$prefix~
        Minus$prefix-
        Greater$infix>
        Greater equal$infix>=
        Less$infix<
        Less equal$infix<=
        Add$infix+
        Subtract$infix-
        Multiply$infix*
        Divide$infix/
        Modulus$infix%
        Power$infix^
        Bitwise and$infix&
        Bitwise or$infix|
        Bitwise xor$infix||
        Bitwise left shift$infix<<
        Bitwise right shift$infix>>
        Index$index
        Set index$setIndex
        Slice$slice
        ^topic +$(htmlContent) #

        Planned Feature

        -

        parent

        -

        Magic functions. #

        -

        Call module. #

        +^topic +$(htmlContent) # +^topic +$(htmlContent) #

        Declare a $call function to allow invoking a module as a function.

        -
        -- Object types are also modules.
        -type Vec2 object:
        +
        -- Object types are also modules.
        +type Vec2:
             var x float
             var y float
         
        @@ -3550,14 +3622,14 @@ 

        Call module. #

        var v = Vec2(1, 2)
        -

        parent

        -

        Getter/Setter. #

        +^topic +$(htmlContent) #

        Planned Feature

        -

        parent

        -

        Missing method. #

        +^topic +$(htmlContent) #

        Declare a $missing method as a fallback when a method was not found in an instance.

        Planned Feature

        -
        type A object:
        +
        type A:
         
             func '$missing'(args...):
                 return args.len
        @@ -3566,70 +3638,75 @@ 

        Missing method. #

        print a.foo() -- Output: '0' print a.bar(1, 2) -- Output: '2'
        -

        parent

        -

        Reflection. #

        -

        A type metatype object references an internal type. Use the typeof builtin to get the metatype of a value.

        -
        var val = 123
        +^topic
        +$(htmlContent) #
        +

        A type metatype object references an internal type. Use the typeof builtin to get the metatype of a value.

        +
        var val = 123
         print typeof(val)   -- 'type: float'
         
         -- Referencing a type as a value also returns its `metatype`.
         print bool          -- 'type: bool'
         
        -

        parent

        -

        Annotations. #

        -

        Annotations are used to attach modifiers to declarative statements. The @host annotation is used for embedding to bind a host function to a Cyber function:

        -
        @host func compute() float
        -
        -

        Custom annotations.

        -

        Planned Feature

        -

        parent

        -

        Runtime eval. #

        +^topic +$(htmlContent) # +

        Directives start with # and are used as modifiers or to invoke compile-time features.

        +

        #genLabel(name string)

        +

        Emits a label during codegen for debugging.

        +

        #host

        +

        Modifier to bind a function, variable, or type to the host. See Embedding.

        +

        #modUri

        +

        Evaluates to the module's URI as a string. See Module URI.

        +

        #with

        +

        Modifier for custom annotations. Planned Feature

        +
        ^topic +$(htmlContent) #

        Planned Feature

        -

        parent

        -

        Generics. #

        +^topic +$(htmlContent) #

        Planned Feature

        -

        parent

        -

        Compile-time. #

        +^topic +$(htmlContent) #

        Planned Feature

        -

        parent

        -

        Embedding. #

        +^topic +$(htmlContent) #
        -

        top

        +

        ^top

        The Embed API allows embedding the Cyber compiler and VM as a library into applications. Cyber's core types and the CLI app were built using the Embed API.

        -

        The API is defined in the C header file. -The examples shown below can be found in the repository under c-embedded. C is used as the host language, but it can be easily translated to C++ or any C-ABI compatible language.

        +

        The API is defined in the C header file. +The examples shown below can be found in the repository under c-embedded. C is used as the host language, but it can be easily translated to C++ or any C-ABI compatible language.

        Types from the Embed API begin with Cs, constants begin with CS, and functions begin with cs.

        -

        Getting started. #

        -

        Create VM. #

        +$(htmlContent) # +^topic +$(htmlContent) #

        Most operations are tied to a VM handle. To create a new VM instance, call csCreate:

        -
        #include "cyber.h"
        +
        #include "cyber.h"
         
         int main() {
             CsVM* vm = csCreate();
        @@ -3638,10 +3715,10 @@ 

        Create VM. #

        return 0; }
        -

        parent

        -

        Override print. #

        +^topic +$(htmlContent) #

        The builtin print function does nothing by default, so it needs to be overrided to print to stdout for example:

        -
        void print(CsVM* vm, CsStr str) {
        +
        void print(CsVM* vm, CsStr str) {
             printf("My print: %.*s\n", (int)str.len, str.buf);
         }
         
        @@ -3651,10 +3728,10 @@ 

        Override print. # // ... }

        -

        parent

        -

        Eval script. #

        +^topic +$(htmlContent) #

        csEval compiles and evaluates a script:

        -
        CsStr src = STR(
        +
        CsStr src = STR(
             "var a = 1\n"
             "print(a + 2)\n"
         );
        @@ -3673,22 +3750,22 @@ 

        Eval script. #

        If a value is returned from the main block of the script, it's saved to the result value argument. Memory is managed by ARC so a value that points to a heap object requires a csRelease when it's no longer needed.

        csEval returns a result code that indicates whether it was successful.

        -

        parent

        -

        Module Loader. #

        +^topic +$(htmlContent) #

        A module loader describes how a module is loaded when an import statement is encountered during script execution. Only one module loader can be active and is set using csSetModuleLoader:

        -
        bool modLoader(CsVM* vm, CsStr spec, CsModuleLoaderResult* out) {
        +
        bool modLoader(CsVM* vm, CsStr spec, CsModuleLoaderResult* out) {
             if (strncmp("my_mod", spec.buf, spec.len) == 0) {
                 out->src =
        -            "@host func add(a float, b float) float\n"
        -            "@host var Root.MyConstant float\n"
        -            "@host var Root.MyList     List\n"
        +            "#host func add(a float, b float) float\n"
        +            "#host var .MyConstant float\n"
        +            "#host var .MyList     List\n"
                     "\n"
        -            "@host\n"
        -            "type MyCollection object:\n"
        -            "    @host func asList() any"
        +            "#host\n"
        +            "type MyCollection:\n"
        +            "    #host func asList() any"
                     "\n"
        -            "@host func MyCollection.new(a, b) MyCollection\n";
        +            "#host func MyCollection.new(a, b) MyCollection\n";
                 out->funcLoader = funcLoader;
                 out->varLoader = varLoader;
                 out->typeLoader = typeLoader;
        @@ -3706,14 +3783,14 @@ 

        Module Loader. #

        }

        The above example checks whether "my_mod" was imported and returns it's source code. Additional loaders are returned to load the functions, variables, and types from the source code.

        -

        parent

        -

        Default module loader. #

        +^topic +$(htmlContent) #

        Since only one module loader can be set to the VM instance, a custom loader is required to handle the "builtins" import which contains all of the core types and functions in Cyber. This can simply be delegated to csDefaultModuleLoader.

        -

        parent

        -

        Function loader. #

        -

        A function loader describes how to load a @host function when it's encountered by the compiler. +^topic +$(htmlContent) # +

        A function loader describes how to load a #host function when it's encountered by the compiler. The loader can bind functions and type methods:

        -
        struct { char* n; CsFuncFn fn; } funcs[] = {
        +
        struct { char* n; CsFuncFn fn; } funcs[] = {
             {"add", add},
             {"asList", myCollectionAsList},
             {"MyCollection.new", myCollectionNew},
        @@ -3729,12 +3806,12 @@ 

        Function loader. #

        } }
        -

        This example uses the CsFuncInfo.idx of a @host function to index into an array and return a Host function pointer. The name is also compared to ensure it's binding to the correct pointer.

        +

        This example uses the CsFuncInfo.idx of a #host function to index into an array and return a Host function pointer. The name is also compared to ensure it's binding to the correct pointer.

        This is an efficient way to map Cyber functions to host functions. A different implementation might use a hash table to map the name of the function to it's pointer.

        -

        parent

        -

        Variable loader. #

        -

        A variable loader describes how to load a @host variable when it's encountered by the compiler:

        -
        // C has limited static initializers (and objects require a vm instance) so initialize them in `main`.
        +^topic
        +$(htmlContent) #
        +

        A variable loader describes how to load a #host variable when it's encountered by the compiler:

        +
        // C has limited static initializers (and objects require a vm instance) so initialize them in `main`.
         typedef struct { char* n; CsValue v; } NameValue;
         NameValue vars[2];
         
        @@ -3753,18 +3830,18 @@ 

        Variable loader. #

        // ... // Initialize var array for loader. - vars[0] = (NameValue){"Root.MyConstant", csFloat(1.23)}; + vars[0] = (NameValue){".MyConstant", csFloat(1.23)}; CsValue myInt = csInteger(123); - vars[1] = (NameValue){"Root.MyList", csNewList(vm, &myInt, 1)}; + vars[1] = (NameValue){".MyList", csNewList(vm, &myInt, 1)}; // ... }

        This example uses the same technique as the function loader, but it can be much simpler. It doesn't matter how the mapping is done as long as the variable loader returns a CsValue.

        -

        parent

        -

        Type loader. #

        -

        A type loader describes how to load a @host type when it's encountered by the compiler:

        -
        CsTypeId myCollectionId;
        +^topic
        +$(htmlContent) #
        +

        A type loader describes how to load a #host type when it's encountered by the compiler:

        +
        CsTypeId myCollectionId;
         
         bool typeLoader(CsVM* vm, CsTypeInfo info, CsTypeResult* out) {
             if (strncmp("MyCollection", info.name.buf, info.name.len) == 0) {
        @@ -3778,21 +3855,21 @@ 

        Type loader. #

        } }
        -

        When binding to the "MyCollection" type, it's typeId is saved to outTypeId. This id is then used to create new instances of this type. See Host types.

        -

        parent

        -

        Host functions. #

        +

        When binding to the "MyCollection" type, it's typeId is saved to outTypeId. This id is then used to create new instances of this type. See Host types.

        +^topic +$(htmlContent) #

        A host function requires a specific function signature:

        -
        CsValue add(CsVM* vm, const CsValue* args, uint8_t nargs) {
        +
        CsValue add(CsVM* vm, const CsValue* args, uint8_t nargs) {
             double res = csAsFloat(args[0]) + csAsFloat(args[1]);
             return csFloat(res);
         }
         

        A host function should always return a CsValue. csNone() can be returned if the function does not intend to return any value.

        -

        parent

        -

        Host types. #

        +^topic +$(htmlContent) #

        A host type are types that are opaque to Cyber scripts but still behave like an object. They can have type functions and methods.

        Only the host application can directly create new instances of them, so usually a function is binded to expose a constructor to the user script:

        -
        // Binding a C struct with it's own children and finalizer.
        +
        // Binding a C struct with it's own children and finalizer.
         // This struct retains 2 VM values and has 2 arbitrary data values unrelated to the VM.
         typedef struct MyCollection {
             CsValue val1;
        @@ -3819,70 +3896,70 @@ 

        Host types. #

        return new; }
        -

        csNewHostObject takes the type id (returned from the Type loader) and size (in bytes) and returns a new heap object. Note that the size is allowed to vary. Different instances of the same type can occupy different amounts of memory.

        -

        parent

        -

        getChildren #

        -

        Since MyCollection contains CsValue children, the Type loader requires a getChildren callback so that memory management can reach them:

        -
        CsValueSlice myCollectionGetChildren(CsVM* vm, void* obj) {
        +

        csNewHostObject takes the type id (returned from the Type loader) and size (in bytes) and returns a new heap object. Note that the size is allowed to vary. Different instances of the same type can occupy different amounts of memory.

        +^topic +$(htmlContent) # +

        Since MyCollection contains CsValue children, the Type loader requires a getChildren callback so that memory management can reach them:

        +
        CsValueSlice myCollectionGetChildren(CsVM* vm, void* obj) {
             MyCollection* my = (MyCollection*)obj;
             return (CsValueSlice){ .ptr = &my->val1, .len = 2 };
         }
         
        -

        parent

        -

        finalizer #

        +^topic +$(htmlContent) #

        A type finalizer is optional since the memory and children of an instance will be freed automatically by ARC. However, it can be useful to perform additional cleanup tasks for instances that contain external resources.

        -
        void myCollectionFinalizer(CsVM* vm, void* obj) {
        +
        void myCollectionFinalizer(CsVM* vm, void* obj) {
             printf("MyCollection finalizer was called.\n");
         }
         
        -

        parent

        -

        Memory. #

        +^topic +$(htmlContent) #
          -
        • ARC.
            -
          • Reference counting.
          • -
          • Optimizations.
          • -
          • Closures.
          • -
          • Fibers.
          • +
          • ARC.
          • -
          • Heap. -

            top

            +

            ^top

            Cyber provides memory safety by default.

            -

            ARC. #

            +$(htmlContent) #

            Cyber uses ARC or automatic reference counting to manage memory. -ARC is deterministic and has less overhead compared to a tracing garbage collector. Reference counting distributes memory management, which reduces GC pauses and makes ARC suitable for realtime applications. One common issue in ARC implementations is reference cycles which Cyber addresses with Weak References and it's very own Cycle Detection.

            -

            parent

            -

            Reference counting. #

            -

            In Cyber, there are primitive and object values. Primitives don't need any memory management, since they are copied by value and no heap allocation is required (with the exception of primitives being captured by a closure.

            +ARC is deterministic and has less overhead compared to a tracing garbage collector. Reference counting distributes memory management, which reduces GC pauses and makes ARC suitable for realtime applications. One common issue in ARC implementations is reference cycles which Cyber addresses with Weak References and it's very own Cycle Detection.

            +^topic +$(htmlContent) # +

            In Cyber, there are primitive and object values. Primitives don't need any memory management, since they are copied by value and no heap allocation is required (with the exception of primitives being captured by a closure.

            Objects are managed by ARC. Each object has its own reference counter. Upon creating a new object, it receives a reference count of 1. When the object is copied, it's retained and the reference count increments by 1. When an object value is removed from it's parent or is no longer reachable in the current stack frame, it is released and the reference count decrements by 1.

            Once the reference count reaches 0 the object begins its destruction procedure. First, child references are released thereby decrementing their reference counts by 1. If the object is a host object, it will invoke its finalizer function. Afterwards, the object is freed from memory.

            -

            parent

            -

            Optimizations. #

            +^topic +$(htmlContent) #

            The compiler can reduce the number of retain/release ops since it can infer value types even though they are dynamically typed to the user. Arguments passed to functions are only retained depending on the analysis from the callsite.

            -

            parent

            -

            Closures. #

            -

            When primitive variables are captured by a closure, they are boxed and allocated on the heap. This means they are managed by ARC and cleaned up when there are no more references to them.

            -

            parent

            -

            Fibers. #

            -

            Fibers are freed by ARC just like any other object. Once there are no references to the fiber, it begins to release it's child references by unwinding it's call stack.

            -

            parent

            -

            Heap. #

            +^topic +$(htmlContent) # +

            When primitive variables are captured by a closure, they are boxed and allocated on the heap. This means they are managed by ARC and cleaned up when there are no more references to them.

            +^topic +$(htmlContent) # +

            Fibers are freed by ARC just like any other object. Once there are no references to the fiber, it begins to release it's child references by unwinding it's call stack.

            +^topic +$(htmlContent) #

            Many object types in Cyber are small enough to be at or under 40 bytes. To take advantage of this, Cyber can reserve object pools to quickly allocate and free these small objects with very little bookkeeping. Bigger objects are allocated and managed by mimalloc which has proven to be a fast and reliable general-purpose heap allocator.

            -

            parent

            -

            Weak references. #

            +^topic +$(htmlContent) #

            Planned Feature

            -

            parent

            -

            Cycle detection. #

            +^topic +$(htmlContent) #

            The cycle detector is also considered a GC and frees abandoned objects managed by ARC. Although weak references can remove cycles altogether, Cyber does not force you to use them and provides a manual GC as a one-time catch all solution.

            Incomplete Feature: Only the main fiber stack is cleaned up at the moment.

            To invoke the GC, call the builtin function: performGC.

            -
            func foo():
            +
            func foo():
                 -- Create a reference cycle.
                 var a = []
                 var b = []
            @@ -3900,22 +3977,21 @@ 

            Cycle detection. #

            print res['numCycFreed'] -- Output: 2 print res['numObjFreed'] -- Output: 2
            -

            parent

            -

            Backends. #

            +^topic +$(htmlContent) # -

            top

            -

            JIT. #

            +

            ^top

            +$(htmlContent) #

            Cyber's just-in-time compiler is incomplete and unstable. To run your script with JIT enabled:

            -
            cyber -jit <script>
            +
            cyber -jit <script>
             

            The JIT compiler is just as fast as the bytecode generation so when it's enabled, the entire script is compiled from the start.

            -

            parent

            -

            AOT #

            +^topic +$(htmlContent) #

            Work on the ahead-of-time compiler has not begun.

            -

            parent