From 6239f278c2c29900ceab901142759cf02c477df0 Mon Sep 17 00:00:00 2001 From: fubark Date: Tue, 19 Sep 2023 18:24:22 +0000 Subject: [PATCH] deploy: f95cd189cf090d26542a87b1d2ced461e75fa1a7 --- 404.html | 2 +- categories/index.html | 2 +- docs/index.html | 2 +- docs/toc/aot-jit/index.html | 2 +- docs/toc/concurrency/index.html | 2 +- docs/toc/control-flow/index.html | 2 +- docs/toc/data-types/index.html | 4 ++-- docs/toc/embedding/index.html | 2 +- docs/toc/errors/index.html | 2 +- docs/toc/ffi/index.html | 2 +- docs/toc/functions/index.html | 2 +- docs/toc/index.html | 2 +- docs/toc/memory/index.html | 2 +- docs/toc/metaprogramming/index.html | 2 +- docs/toc/modules/index.html | 2 +- docs/toc/syntax/index.html | 2 +- docs/toc/type-system/index.html | 2 +- ...68c0945db3e2bd7104c96864b46b7af194f2f9ed362e8497c3c19.json | 1 + ...03bc62a33db6550710b275db6444d7746b904b7478ba4f6d1db4f.json | 1 - ...6fe1829b7c32e1613e5e896d742a3010e5975362d629f119703c98d.js | 2 +- index.html | 2 +- tags/index.html | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) create mode 100644 en.search-data.min.7c9bee2bed668c0945db3e2bd7104c96864b46b7af194f2f9ed362e8497c3c19.json delete mode 100644 en.search-data.min.fcf6482b69d03bc62a33db6550710b275db6444d7746b904b7478ba4f6d1db4f.json rename en.search.min.436a98919e3cc9dc331a63b9d377785de95eec900cfb65b7ed9a0acf873a4d8a.js => en.search.min.db402b8c46fe1829b7c32e1613e5e896d742a3010e5975362d629f119703c98d.js (90%) diff --git a/404.html b/404.html index bd95ad27a..0e724a766 100644 --- a/404.html +++ b/404.html @@ -1,5 +1,5 @@ 404 Page not found | Cyber Docs v0.2 - +

404

Page Not Found

Cyber Docs v0.2

\ No newline at end of file diff --git a/categories/index.html b/categories/index.html index d52eae494..f2036a8c2 100644 --- a/categories/index.html +++ b/categories/index.html @@ -1,5 +1,5 @@ Categories | Cyber Docs v0.2 - +
Categories diff --git a/docs/index.html b/docs/index.html index 044ed3f50..c7dd844c6 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,5 +1,5 @@ Docs | Cyber Docs v0.2 - +
Docs diff --git a/docs/toc/aot-jit/index.html b/docs/toc/aot-jit/index.html index 74c2c6fbf..6619ab975 100644 --- a/docs/toc/aot-jit/index.html +++ b/docs/toc/aot-jit/index.html @@ -1,5 +1,5 @@ AOT/JIT | Cyber Docs v0.2 - +
AOT/JIT diff --git a/docs/toc/concurrency/index.html b/docs/toc/concurrency/index.html index 652aa7139..3164bb419 100644 --- a/docs/toc/concurrency/index.html +++ b/docs/toc/concurrency/index.html @@ -3,7 +3,7 @@ The coinit creates a new fiber from a function call syntax. Using coyield inside a function pauses the current fiber and execution is returned to the fiber that invoked coresume.">Concurrency | Cyber Docs v0.2 - +
Concurrency diff --git a/docs/toc/control-flow/index.html b/docs/toc/control-flow/index.html index f5b09d3b3..9aca892db 100644 --- a/docs/toc/control-flow/index.html +++ b/docs/toc/control-flow/index.html @@ -3,7 +3,7 @@ var a = 10 if a == 10: print 'a is 10' else a == 20: print 'a is 20' else: print 'neither 10 nor 20' An if expression also needs the then keyword.">Control Flow | Cyber Docs v0.2 - +
Control Flow diff --git a/docs/toc/data-types/index.html b/docs/toc/data-types/index.html index 3eba03a57..26b85e515 100644 --- a/docs/toc/data-types/index.html +++ b/docs/toc/data-types/index.html @@ -1,7 +1,7 @@ Data Types | Cyber Docs v0.2 - +
Data Types @@ -245,7 +245,7 @@ }

Entries can also follow a {}: block. This gives structure to the entries and has -the added benefit of allowing multi-line lambdas.

var colors = {}:
+the added benefit of allowing multi-line lambdas.

Planned Feature

var colors = {}:
     red: 0xFF0000
     green: 0x00FF00
     blue: 0x0000FF
diff --git a/docs/toc/embedding/index.html b/docs/toc/embedding/index.html
index 7a83d14b7..0ba667c5d 100644
--- a/docs/toc/embedding/index.html
+++ b/docs/toc/embedding/index.html
@@ -1,5 +1,5 @@
 Embedding | Cyber Docs v0.2
-
+
 
 
Embedding diff --git a/docs/toc/errors/index.html b/docs/toc/errors/index.html index 542fc485c..291d18eab 100644 --- a/docs/toc/errors/index.html +++ b/docs/toc/errors/index.html @@ -1,7 +1,7 @@ Error Handling | Cyber Docs v0.2 - +
Error Handling diff --git a/docs/toc/ffi/index.html b/docs/toc/ffi/index.html index e7d24008e..887a672ff 100644 --- a/docs/toc/ffi/index.html +++ b/docs/toc/ffi/index.html @@ -1,7 +1,7 @@ FFI | Cyber Docs v0.2 - +
FFI diff --git a/docs/toc/functions/index.html b/docs/toc/functions/index.html index 13417f5ad..5b119092d 100644 --- a/docs/toc/functions/index.html +++ b/docs/toc/functions/index.html @@ -5,7 +5,7 @@ Static Functions. # 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 m 'math' func dist(x0, y0, x1, y1): var dx = x0-x1 var dy = y0-y1 return m.">Functions | Cyber Docs v0.2 - +
Functions diff --git a/docs/toc/index.html b/docs/toc/index.html index 9d81635df..9c0d95e30 100644 --- a/docs/toc/index.html +++ b/docs/toc/index.html @@ -1,5 +1,5 @@ Table of Contents | Cyber Docs v0.2 - +
Table of Contents diff --git a/docs/toc/memory/index.html b/docs/toc/memory/index.html index 614c91d31..696e8ef05 100644 --- a/docs/toc/memory/index.html +++ b/docs/toc/memory/index.html @@ -1,7 +1,7 @@ Memory | Cyber Docs v0.2 - +
Memory diff --git a/docs/toc/metaprogramming/index.html b/docs/toc/metaprogramming/index.html index e4b936462..6ba0b2e3d 100644 --- a/docs/toc/metaprogramming/index.html +++ b/docs/toc/metaprogramming/index.html @@ -5,7 +5,7 @@ Incomplete: Not all operators have transitioned to the method paradigm. Normally this would impact performance, but Cyber’s compiler generates specialized bytecode ops for builtin types like int and float. The VM performs inline caching at runtime to eliminate the overhead of evaluating operators on dynamic operands. To overload an operator for a object type, declare $prefix, $infix, $postfix methods:">Metaprogramming | Cyber Docs v0.2 - +
Metaprogramming diff --git a/docs/toc/modules/index.html b/docs/toc/modules/index.html index 623f097d4..a9a81a577 100644 --- a/docs/toc/modules/index.html +++ b/docs/toc/modules/index.html @@ -1,7 +1,7 @@ Modules | Cyber Docs v0.2 - +
Modules diff --git a/docs/toc/syntax/index.html b/docs/toc/syntax/index.html index 0974c1d0d..94ef6305f 100644 --- a/docs/toc/syntax/index.html +++ b/docs/toc/syntax/index.html @@ -5,7 +5,7 @@ Statements. # A statement ends with the new line. -- An assignment statement. var a = 123 Blocks. # A new block starts with a colon. This is intended to give structure to nested statements without an ending delimiter. -- This `if` statement begins a new block. if true: var a = 234 The first statement in a block must be indented further.">Syntax | Cyber Docs v0.2 - +
Syntax diff --git a/docs/toc/type-system/index.html b/docs/toc/type-system/index.html index 528ede352..f7b412658 100644 --- a/docs/toc/type-system/index.html +++ b/docs/toc/type-system/index.html @@ -3,7 +3,7 @@ Dynamic typing can reduce the amount of friction when writing code, but it can also result in more runtime errors.">Type System | Cyber Docs v0.2 - +
Type System diff --git a/en.search-data.min.7c9bee2bed668c0945db3e2bd7104c96864b46b7af194f2f9ed362e8497c3c19.json b/en.search-data.min.7c9bee2bed668c0945db3e2bd7104c96864b46b7af194f2f9ed362e8497c3c19.json new file mode 100644 index 000000000..06e82c7df --- /dev/null +++ b/en.search-data.min.7c9bee2bed668c0945db3e2bd7104c96864b46b7af194f2f9ed362e8497c3c19.json @@ -0,0 +1 @@ +[{"id":0,"href":"/cyber/docs/toc/syntax/","title":"Syntax","section":"Table of Contents","content":" Syntax # Cyber\u0026rsquo;s syntax is concise and easy to read.\nStatements. # A statement ends with the new line.\n-- An assignment statement. var a = 123 Blocks. # A new block starts with a colon. This is intended to give structure to nested statements without an ending delimiter.\n-- This `if` statement begins a new block. if true: var a = 234 The first statement in a block must be indented further. Spaces or tabs can be used for indentation but not both. Subsequent statements in the block must follow the same indentation. The block ends when a statement recedes from this indentation.\nfor items each it: if it == 20: print it 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.\n-- 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. print 234 Variables. # In Cyber, there are local variables and static variables.\nLocal Variables. # Local variables exist until the end of their scope. They are declared and initialized using the var keyword.\n-- Declaration. var a = 123 -- Subsequent assignment. a = 234 A new variable can be declared in function blocks with the same name as a variable from a parent block.\nvar a = 123 foo = func(): -- A new local `a` inside function `foo`. var a = 234 foo() print a -- \u0026#39;123\u0026#39; However, variables declared in sub-blocks such as if and for can not shadow variables in the same main/function block.\nvar a = 123 if true: -- CompileError, `a` is already declared in the main block. var a = 234 When a parent local is referenced in a lambda function, the variable is automatically captured. Note that static functions can not capture parent locals.\nIncomplete: Only variables one parent block away can be captured.\nvar a = 123 var foo = func(): a = 234 foo() print a -- \u0026#39;234\u0026#39; Static Variables. # Static variables live until the end of the script. They act as global variables and are visible from anywhere in the script.\nStatic variables are also declared with var but : is used instead of = to initialize a value to them.\nvar a: 123 func foo(): print a -- \u0026#39;123\u0026#39; Static variables are always exported from the current script. You can read more about exports and Modules.\nWhen declared in functions, static variables are initialized once and continue to exist for subsequent function calls.\nPlanned Feature\nfunc add(a): var sum: 0 sum += a return sum print add(5) -- \u0026#39;5\u0026#39; print add(5) -- \u0026#39;10\u0026#39; Since static variable declarations are initialized outside of a fiber\u0026rsquo;s execution flow, they can not reference any local variables.\nvar a = 123 var b: a -- Compile error, initializer can not reference a local variable. However, you can reassign any value to them with an assignment statement.\nvar a = 123 var b: 0 b = a -- Reassigning can reference a local variable. 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. The following would print \u0026lsquo;123\u0026rsquo; before \u0026lsquo;234\u0026rsquo;\nvar 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.\nvar a: b + 321 var b: 123 print a -- \u0026#39;444\u0026#39; Circular references in initializers are allowed. When initialization encounters a reference that creates this circular dependency, that reference evaluates to none. In the following, a attempts to initialize first because of its natural ordering. Since b is a dependency, it supersedes the natural ordering. When b is found to reference an already visited a (causing the circular dependency), it evaluatues to a\u0026rsquo;s current value which is none. At the end of initialization, both a and b have the value none.\nvar a: b var b: a 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.\nPlanned Feature\nvar myImage: var img = loadImage(\u0026#39;me.png\u0026#39;) 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.\nKeywords. # There are currently 33 keywords in Cyber. This list categorizes them and shows you when you might need them.\nControl Flow: if then else match while for each break continue pass some Operators: or and not is Variables: var as Functions: func return Coroutines: coinit coyield, coresume Data Types: type object enum true false none Error Handling: try catch error throw Modules: import Operators. # Cyber supports the following operators. They are ordered from highest to lowest precedence.\nOperator Description \u0026lt;\u0026lt; \u0026gt;\u0026gt; Bitwise left shift, right shift. \u0026amp; Bitwise and. | || Bitwise or, exclusive or. ^ Power. / % * Division, modulus, multiplication. + - Addition, subtraction. as Type casting. \u0026gt; \u0026gt;= \u0026lt; \u0026lt;= != == Greater, greater or equal, less, less or equal, not equals, equals. and Logical and. or Logical or. Arithmetic Operators. # The following arithmetic operators are supported for the numeric data types.\n1 + 2 -- Addition, evaluates to 3. 100 - 10 -- Subtraction, evaluates to 90. 3 * 4 -- Multiplication, evaluates to 12. 20 / 5 -- Division, evaluates to 4. 2 ^ 4 -- Raise to the power, evaluates to 16. 12 % 5 -- Modulus remainder, evaluates to 2. -(10) -- Apply negative, evaluates to -10. Comparison Operators. # Cyber supports the following comparison operators. By default, a comparison operator evaluates to a Boolean value.\nThe 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.\n1 == 1 -- Evaluates to `true` 1 == 2 -- Evaluates to `false` 1 == true -- Evaluates to `false` var a = \u0026#39;abc\u0026#39; a == \u0026#39;abc\u0026#39; -- Evaluates to `true` a = [] b = a a == b -- Evaluates to `true` a == [] -- Evaluates to `false` The not equals operator returns true if the two values are not equal.\n1 != 1 -- Evaluates to `false` 1 != 2 -- Evaluates to `true` Number types have additional comparison operators.\na \u0026gt; b -- `true` if a is greater than b a \u0026gt;= b -- `true` if a is greater than or equal to b a \u0026lt; b -- `true` if a is less than b a \u0026lt;= b -- `true` if a is less than or equal to b Logic Operators. # The logical operators and, or, and not are supported.\nand 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\u0026rsquo;t 0 is truthy. An object reference is always truthy. The none value is not truthy.\ntrue 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.\ntrue 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.\nnot false -- Evaluates to true not true -- Evaluates to false not 0 -- Evaluates to true not 123 -- Evaluates to false !false -- Evaluates to true !true -- Evaluates to false Bitwise Operators. # The following bitwise operators are supported for int number values.\n-- Bitwise and: any underlying bits that are set in both integers are set in the new integer. a \u0026amp; b -- Bitwise or: any underlying bits that are set in either integer a or integer b are set in the new integer. a | b -- Bitwise exclusive or: any underlying bits that are set in either integer a or integer b but not both are set in the new integer. a || b -- Bitwise right shift: a\u0026#39;s bits are shifted b bits to the least significant end. This performs sign-extension on the 32-bit integer. a \u0026gt;\u0026gt; b -- Bitwise left shift: a\u0026#39;s bits are shifted b bits to the most significant end. This does not perform sign-extension on the 32-bit integer. a \u0026lt;\u0026lt; b -- Bitwise not: a\u0026#39;s integer bits are flipped. ~a Operator Overloading. # See Operator Overloading in Metaprogramming.\nComments. # A single line comment starts with two hyphens and ends at the end of the line.\n-- 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.\nCYON. # CYON or the Cyber object notation is similar to JSON. The format uses the same literal value semantics as Cyber.\n{ name: \u0026#39;John Doe\u0026#39; \u0026#39;age\u0026#39;: 25 -- This is a comment cities: [ \u0026#39;New York\u0026#39; \u0026#39;San Francisco\u0026#39; \u0026#39;Tokyo\u0026#39; ] } "},{"id":1,"href":"/cyber/docs/toc/data-types/","title":"Data Types","section":"Table of Contents","content":" Data Types. # In Cyber, there are primitive types and object types. Primitives are copied around by value and don\u0026rsquo;t need additional heap memory or reference counts. Primitives include Booleans, Floats, Integers, Enums, Symbols, Errors, Static Strings, and the none value. Object types include Lists, Maps, Strings, Custom Objects, Lambdas, Fibers, Errors with payloads, Pointers, and several internal object types.\nThe none value represents an empty value. This is similar to null in other languages.\nBooleans. # Booleans can be true or false.\nvar a = true if a: print \u0026#39;a is true\u0026#39; When other value types are coerced to the boolean type, the truthy value is determined as follows.\nThe none value is false. Other objects and values are always true. Numbers. # Integers. # int is the default integer type. It has 48-bits and can represent integers in the range -(247) to 247-1.\nWhen a numeric literal is used and the type can not be inferred, it will default to the int type:\nvar a = 123 Integer notations always produce a int value:\nvar a = 0xFF -- hex. a = 0o17 -- octal. a = 0b1010 -- binary. a = 0u\u0026#39;🐶\u0026#39; -- UTF-8 rune. Arbitrary values can be converted to a int using the type as a function.\nvar a = \u0026#39;123\u0026#39; var b = int(a) In addition to arithmetic operations, integers can also perform bitwise operations.\nFloats. # float is the default floating point type. It has a (IEEE 754) 64-bit floating point format.\nAlthough 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.\nA numeric literal can be used to create a float if the inferred type is a float:\na float = 123 Decimal and scientific notations always produce a float value:\nvar a = 2.34567 var b = 123.0e4 Arbitrary values can be converted to a float using the type as a function.\nvar a = \u0026#39;12.3\u0026#39; var b = float(a) Big Numbers. # Planned Feature\nStrings. # 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. Under the hood, Cyber implements 6 different internal string types to optimize string operations, but the user just sees them as one type and doesn\u0026rsquo;t need to care about this detail under normal usage.\nStrings 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 the StringBuffer.\nPlanned Feature\nA string is always UTF-8 validated. rawstrings outperform strings but you\u0026rsquo;ll have to validate them and take care of indexing yourself.\nA single line string literal is surrounded in single quotes.\nvar apple = \u0026#39;a fruit\u0026#39; You can escape the single quote inside the literal or use double quotes.\nvar apple = \u0026#39;Bob\\\u0026#39;s fruit\u0026#39; apple = \u0026#34;Bob\u0026#39;s fruit\u0026#34; Strings are UTF-8 encoded.\nvar str = \u0026#39;abc🦊xyz🐶\u0026#39; Use double quotes to surround a multi-line string.\nvar str = \u0026#34;line a line b line c\u0026#34; You can escape double quotes inside the literal or use triple quotes.\nvar str = \u0026#34;line a line \\\u0026#34;b\\\u0026#34; line c\u0026#34; -- Using triple quotes. str = \u0026#39;\u0026#39;\u0026#39;line a line \u0026#34;b\u0026#34; line c \u0026#39;\u0026#39;\u0026#39; The following escape sequences are supported:\nEscape Sequence Code Description \\a 0x07 Terminal bell. \\b 0x08 Backspace. \\e 0x1b Escape character. \\n 0x0a Line feed character. \\r 0x0d Carriage return character. \\t 0x09 Horizontal tab character. The boundary of each line can be set with a vertical line character. This makes it easier to see the whitespace.\nvar poem = \u0026#34;line a | two spaces from the left | indented further\u0026#34; 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().\nvar str = \u0026#39;abcd\u0026#39; print str[1] -- \u0026#34;b\u0026#34; print str[-1] -- \u0026#34;d\u0026#34; Using the slice index 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\u0026rsquo;s length.\nvar str = \u0026#39;abcxyz\u0026#39; var sub = str[0..3] print sub -- \u0026#34;abc\u0026#34; print str[..5] -- \u0026#34;abcxy\u0026#34; print str[1..] -- \u0026#34;bcxyz\u0026#34; -- One way to use slices is to continue a string operation. str = \u0026#39;abcabcabc\u0026#39; var i = str.findRune(0u\u0026#39;c\u0026#39;) print(i) -- \u0026#34;2\u0026#34; i += 1 print(i + str[i..].findRune(0u\u0026#39;c\u0026#39;)) -- \u0026#34;5\u0026#34; type string # func concat(self, str string) string -- Returns a new string that concats this string and `str`. func endsWith(self, suffix string) bool -- Returns whether the string ends with `suffix`. func find(self, needle string) int? -- Returns the first index of substring `needle` in the string or `none` if not found. func findAnyRune(self, set string) int? -- Returns the first index of any UTF-8 rune in `set` or `none` if not found. func findRune(self, needle int) int? -- Returns the first index of UTF-8 rune `needle` in the string or `none` if not found. func insert(self, idx int, str string) string -- Returns a new string with `str` inserted at index `idx`. func isAscii(self) bool -- Returns whether the string contains all ASCII runes. func len(self) int -- Returns the number of UTF-8 runes in the string. func less(self, str string) bool -- Returns whether this string is lexicographically before `str`. func lower(self) string -- Returns this string in lowercase. func replace(self, needle string, replacement string) string -- Returns a new string with all occurrences of `needle` replaced with `replacement`. | func repeat(self, n int) string -- Returns a new string with this string repeated `n` times. func runeAt(self, idx int) int -- Returns the UTF-8 rune at index `idx`. func slice(self, start int, end int) string -- Returns a slice into this string from `start` to `end` (exclusive) indexes. This is equivalent to using the slice index operator `[start..end]`. func sliceAt(self, idx int) string -- Returns the UTF-8 rune at index `idx` as a single rune string. func split(self, delim string) List -- Returns a list of UTF-8 strings split at occurrences of `delim`. func startsWith(self, prefix string) bool -- Returns whether the string starts with `prefix`. func trim(self, mode symbol, trimRunes any) string -- Returns the string with ends trimmed from runes in `trimRunes`. `mode` can be #left, #right, or #ends. func upper(self) string -- Returns this string in uppercase. String Interpolation. # You can embed expressions into string templates using braces.\nvar name = \u0026#39;Bob\u0026#39; var points = 123 var str = \u0026#39;Scoreboard: {name} {points}\u0026#39; Escape braces with a backslash.\nvar points = 123 var str = \u0026#39;Scoreboard: \\{ Bob \\} {points}\u0026#39; String templates can not contain nested string templates.\nrawstring. # A rawstring does not automatically validate the string and is indexed by bytes and not UTF-8 runes.\nUsing the index operator will return the UTF-8 rune starting at the given byte index as a slice. If the index does not begin a valid UTF-8 rune, error.InvalidRune is returned. This is equivalent to calling the method sliceAt().\nvar str = rawstring(\u0026#39;abcd\u0026#39;).insertByte(1, 255) print str[0] -- \u0026#34;a\u0026#34; print str[1] -- error.InvalidRune print str[-1] -- \u0026#34;d\u0026#34; type rawstring # func byteAt(self, idx int) int -- Returns the byte value (0-255) at the given index `idx`. func concat(self, str string) string -- Returns a new string that concats this string and `str`. func endsWith(self, suffix string) bool -- Returns whether the string ends with `suffix`. func find(self, needle string) int? -- Returns the first index of substring `needle` in the string or `none` if not found. func findAnyRune(self, set string) int? -- Returns the first index of any UTF-8 rune in `set` or `none` if not found. func findRune(self, needle int) int? -- Returns the first index of UTF-8 rune `needle` in the string or `none` if not found. func insert(self, idx int, str string) string -- Returns a new string with `str` inserted at index `idx`. func insertByte(self, idx int, byte int) string -- Returns a new string with `byte` inserted at index `idx`. func isAscii(self) bool -- Returns whether the string contains all ASCII runes. func len(self) int -- Returns the number of bytes in the string. func less(self, str rawstring) bool -- Returns whether this rawstring is lexicographically before `str`. func lower(self) string -- Returns this string in lowercase. func repeat(self, n int) rawstring -- Returns a new rawstring with this rawstring repeated `n` times. func replace(self, needle string, replacement string) string -- Returns a new string with all occurrences of `needle` replaced with `replacement`. func runeAt(self, idx int) int -- Returns the UTF-8 rune at index `idx`. If the index does not begin a UTF-8 rune, `error.InvalidRune` is returned. func slice(self, start int, end int) rawstring -- Returns a slice into this string from `start` to `end` (exclusive) indexes. This is equivalent to using the slice index operator `[start..end]`. func sliceAt(self, idx int) string -- Returns the UTF-8 rune at index `idx` as a single rune string. If the index does not begin a UTF-8 rune, `error.InvalidRune` is returned. func split(self, delim string) List -- Returns a list of rawstrings split at occurrences of `delim`. func startsWith(self, prefix string) bool -- Returns whether the string starts with `prefix`. func upper(self) string -- Returns this string in uppercase. func trim(self, mode symbol, trimRunes any) rawstring -- Returns the string with ends trimmed from runes in `trimRunes`. `mode` can be #left, #right, or #ends. func utf8(self) string -- Returns a valid UTF-8 string or returns `error.InvalidRune`. Lists. # Lists are a builtin type that holds an ordered collection of elements. Lists grow or shrink as you insert or remove elements.\n-- Construct a new list. var list = [1, 2, 3] -- The first element of the list starts at index 0. print list[0] -- Prints \u0026#39;1\u0026#39; -- Using a negative index starts at the back of the list. print list[-1] -- Prints \u0026#39;3\u0026#39; 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. Negative start or end values count from the end of the list.\nvar list = [ 1, 2, 3, 4, 5 ] list[0..0] -- [] Empty list. list[0..3] -- [ 1, 2, 3 ] From start to end index. list[3..] -- [ 4, 5 ] From start index to end of list. list[..3] -- [ 1, 2, 3 ] From start of list to end index. list[2..+2] -- [ 3, 4 ] From start index to start index + amount. List operations.\nvar list = [234] -- Append a value. list.append 123 print list[-1] -- Prints \u0026#39;123\u0026#39; -- Inserting a value at an index. list.insert(1, 345) -- Get the length. print list.len() -- Prints \u0026#39;2\u0026#39; -- Sort the list in place. list.sort((a, b) =\u0026gt; a \u0026lt; b) -- Iterating a list. for list each it: print it -- Remove an element at a specific index. list.remove(1) type List # Method Summary append(val any) none Appends a value to the end of the list. concat(val any) none Concats the elements of another list to the end of this list. insert(idx int, val any) none Inserts a value at index idx. iterator() Iterator\u0026lt;any\u0026gt; Returns a new iterator over the list elements. joinString(separator any) string Returns a new string that joins the elements with separator. len() int Returns the number of elements in the list. pairIterator() PairIterator\u0026lt;int, any\u0026gt; Returns a new pair iterator over the list elements. remove(idx int) none Removes an element at index idx. resize(len int) none Resizes the list to len elements. If the new size is bigger, none values are appended to the list. If the new size is smaller, elements at the end of the list are removed. sort(less func (a, b) bool) none Sorts the list with the given less function. If element a should be ordered before b, the function should return true otherwise false. Maps. # Maps are a builtin type that store key value pairs in dictionaries.\nvar map = { a: 123, b: () =\u0026gt; 5 } print map[\u0026#39;a\u0026#39;] -- You can also access the map using an access expression. print map.a -- Map entries can be separated by the new line. map = { foo: 1 bar: 2 } Entries can also follow a {}: block. This gives structure to the entries and has the added benefit of allowing multi-line lambdas.\nPlanned Feature\nvar colors = {}: red: 0xFF0000 green: 0x00FF00 blue: 0x0000FF dump func (c): print c.red print c.green print c.blue -- Nested map. darker {}: red: 0xAA0000 green: 0x00AA00 blue: 0x0000AA Map operations.\nvar map = {} -- Set a key value pair. map[123] = 234 -- Get the size of the map. print map.size() -- Remove an entry by key. map.remove 123 -- Iterating a list. for map each val, key: print \u0026#39;{key} -\u0026gt; {value}\u0026#39; type Map # Method Summary iterator() Iterator\u0026lt;any\u0026gt; Returns a new iterator over the map elements. pairIterator() PairIterator\u0026lt;any, any\u0026gt; Returns a new pair iterator over the map elements. remove(key any) none Removes the element with the given key key. size() int Returns the number of key-value pairs in the map. Objects. # Any value that isn\u0026rsquo;t a primitive is an object. You can declare your own object types using the type object declaration. Object types are similar to structs and classes in other languages. You can declare members and methods. Unlike classes, there is no concept of inheritance at the language level.\ntype Node object: value next var node = Node{ value: 123, next: none } print node.value -- \u0026#39;123\u0026#39; New instances of an object template are created using the type name and braces that surround the initial member values.\nMethods. # The first parameter of a method must be self. Otherwise, it declares a static function that can only be invoked from the type\u0026rsquo;s namespace.\ntype Node object: value next -- A static function. func create(): return Node{ value: 123, next: none } -- A method. func dump(self): print self.value var n = Node.create() n.dump() Although self is required in a method\u0026rsquo;s signature, it\u0026rsquo;s optional when referencing the type\u0026rsquo;s members.\ntype Node object: value func double(self): return value * 2 Enums. # 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.\ntype Fruit enum: apple orange banana kiwi var fruit = Fruit.kiwi print fruit -- \u0026#39;Fruit.kiwi\u0026#39; print int(fruit) -- \u0026#39;3\u0026#39; When the type of the value is known to be an enum, it can be assigned using a symbol literal.\nvar fruit = Fruit.kiwi fruit = #orange print(fruit == Fruit.orange) -- \u0026#39;true\u0026#39; Symbols. # Symbol literals begin with #, followed by an identifier. They have their own global unique id.\nvar currency = #usd print(currency == #usd) -- \u0026#39;true\u0026#39; print int(currency) -- \u0026#39;123\u0026#39; or some arbitrary id. "},{"id":2,"href":"/cyber/docs/toc/control-flow/","title":"Control Flow","section":"Table of Contents","content":" Control Flow. # Cyber provides the common constructs to branch and enter loops.\nBranching. # 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.\nvar a = 10 if a == 10: print \u0026#39;a is 10\u0026#39; else a == 20: print \u0026#39;a is 20\u0026#39; else: print \u0026#39;neither 10 nor 20\u0026#39; An if expression also needs the then keyword. Conditional else clauses are not allowed in an if expression.:\nvar a = 10 var str = if a == 10 then \u0026#39;red\u0026#39; else \u0026#39;blue\u0026#39; Use and and or logical operators to combine conditions:\nvar a = 10 if a \u0026gt; 5 and a \u0026lt; 15: print \u0026#39;a is between 5 and 15\u0026#39; if a == 20 or a == 10: print \u0026#39;a is 10 or 20\u0026#39; Iterations. # Infinite and conditional loops start with the while keyword. An infinite loop continues to run the code in the block until a break or return is reached. When the while clause contains a condition, the loop continues to run until the condition is evaluated to false.\n-- Infinite loop. while: pass var running = true while running: -- Keep looping until `running` is false. pass You can use the optional while loop to continue the loop until the expression evaluates to the none value. The unwrapped optional value is copied to the variable declared after some.\nvar iter = dir.walk() while iter.next() some entry: print entry.name for loops can iterate over a range that starts at a int (inclusive) to a target int (exclusive). When the range operator .. is replaced with ..=, the target int is inclusive. The range can be given a custom step.\nfor 0..100 each i: print i -- 0, 1, 2, ... , 99 for 0..100, 10 each i: print i -- 0, 10, 20, ... , 90 for 100..0, 1 each i: print i -- 100, 99, 98, ... , 1 for 100..=0, 1 each i: print i -- 100, 99, 98, ... , 0 The for clause can iterate over an Iterable object. An Iterable type contains an iterator() method that returns an Iterator object. An Iterator type contains a next() method that returns the next value or none when finished. You can iterate lists since they are Iterable.\nvar list = [1, 2, 3, 4, 5] -- Iterate on values. for list each n: print n When the as clause contains two variables, the for loop will iterate a PairIterable object. A PairIterable type contains a pairIterator() method that returns a PairIterator object. A PairIterator type contains a nextPair() method that returns two values or none on the first value when finished. The list object is also a PairIterable and the key is the index of the value in the list.\n-- Iterate on values and indexes. for list each i, n: print \u0026#39;{i} -\u0026gt; {n}\u0026#39; -- Iterate on just indexes. for list each i, _: print i The for clause can also iterate over maps with the same idea.\nvar map = { a: 123, b: 234 } -- Iterate on values. for map each v: print v -- Iterate on values and keys. for map each k, v: print \u0026#39;{k} -\u0026gt; {v}\u0026#39; -- Iterate on just keys. for map each k, _: print k You can exit a loop using break.\nfor 0..10 each i: if i == 4: break print i -- This loop stops printing once `i` reaches 4. You can skip the rest of the loop and go to the next iteration using continue.\nfor 0..10 each i: if i == 4: continue print i -- This loop prints 0 through 9 but skips 4. Matching. # Matching is similar to a switch statement. The expression to the right of match is evaluated and execution jumps to the declared case with the matching value. Multiple cases can be grouped together using a comma separator. An optional else fallback case is executed when no other cases were matched.\nIncomplete: Not all types can be used in the case clause such as ranges.\nvar val = 1000 match val: 0..100: print \u0026#39;at or between 0 and 99\u0026#39; 100: print \u0026#39;val is 100\u0026#39; 200: print \u0026#39;val is 200\u0026#39; 300, 400: print \u0026#39;combined case\u0026#39; else: print \u0026#39;val is {val}\u0026#39; 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.\nDeferred Execution. # Planned Feature\n"},{"id":3,"href":"/cyber/docs/toc/functions/","title":"Functions","section":"Table of Contents","content":" Functions. # In Cyber, there are first-class functions (or function values) and static functions.\nStatic Functions. # Static functions are not initially values themselves. They allow function calls to be optimal since they don\u0026rsquo;t need to resolve a dynamic value.\nStatic functions are declared with the func keyword and must have a name.\nimport m \u0026#39;math\u0026#39; func dist(x0, y0, x1, y1): var dx = x0-x1 var dy = y0-y1 return m.sqrt(dx^2 + dy^2) Calling static functions is straightforward. You can also reassign or pass them around as function values.\nprint dist(0, 0, 10, 20) -- Assigning to a local variable. var bar = dist -- Passing `dist` as an argument. func squareDist(dist, size): return dist(0, 0, size, size) print squareDist(dist, 30) The function declaration can also be initialized to an expression that evaluates to a function. However, the expression can not contain any local variable references since it\u0026rsquo;s a static declaration. The function signatures also have to match.\nfunc myAdd(a, b): return a + b func add(a, b) = myAdd -- Valid declaration. var myInc = func(a): return a + 1 func inc(a) = myInc -- CompileError, referencing local variable `myInc`. func foo(a, b, c) = myAdd -- panic, signature mismatch. Functions can return multiple values. This feature has not been confirmed nor implemented.\nimport {cos, sin} \u0026#39;math\u0026#39; func compute(rad): return cos(rad), sin(rad) var x, y = compute(pi) Function Overloading. # Static functions can be overloaded by the number of parameters in its signature. Typed functions are further overloaded by its type signature.\nfunc foo(): return 2 + 2 func foo(n): return 10 + n func foo(n, m): return n * m print foo() -- \u0026#34;4\u0026#34; print foo(2) -- \u0026#34;12\u0026#34; print foo(20, 5) -- \u0026#34;100\u0026#34; Lambdas. # Lambdas or function values can be assigned to variables or passed as arguments into other constructs.\nWhen a lambda only returns an expression, it can be declared with a simplified syntax.\n-- Passing simple lambda as an argument. foo(word =\u0026gt; toUpper(word)) -- A simple lambda with multiple arguments. foo((word, prefix) =\u0026gt; prefix + toUpper(word)) -- Assigning a simple lambda. canvas.onUpdate = delta_ms =\u0026gt; print delta_ms Lambdas that need a block of statements can be declared with the func keyword without a name.\n-- Assigning lambda block to a variable. var add = func (a, b): return a + b -- Passing a lambda block as an argument. canvas.onUpdate(): ..func (delta_ms): print delta_ms Passing a lambda block as a call argument is only possible in a call block. See Function Calls.\nClosures. # In Cyber, lambdas can capture local variables from parent blocks. This example shows the lambda f capturing a from the main scope.\nvar a = 1 var f = func(): return a + 2 print f() -- \u0026#34;3\u0026#34; The following lambda expression captures a from the function add.\nfunc add(): var a = 123 return b =\u0026gt; a + b var addTo = add() print addTo(10) -- \u0026#34;133\u0026#34; However, static functions can not capture local variables.\nvar a = 1 func foo(): print a -- Compile Error: Can\u0026#39;t reference local from static function. Named Parameters. # Planned Feature\nOptional Parameters. # Planned Feature\nVariadic Parameters. # Planned Feature\nFunction Calls. # The straightforward way to call a function is to use parentheses.\nvar d = dist(100, 100, 200, 200) You can call functions with named parameters.\nvar d = dist(x0: 10, x1: 20, y0: 30, y1: 40) The shorthand method for calling functions omits parentheses and commas. This only works for functions that accept parameters:\nIncomplete: Only the most trivial cases work with the shorthand method. The case with operators being separated by spaces might not end up being implemented.\nvar d = dist 100 100 200 200 -- Calls the function `dist`. func random(): -- Function with no parameters. return 4 var r = random -- Returns the function itself as a value. Does not call the function `random`. r = random() -- Calls the function `random`. The top level arguments for the shorthand convention must be separated by whitespace. A string can contain whitespace since it\u0026rsquo;s surrounded by delimiters.\nvar a = myFunc \u0026#39;cyber script\u0026#39; The following has a binary expression with spaces inbetween which is not allowed. Removing that whitespace fixes the call expression.\nvar 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.\n-- This calls the function `myFunc` with 2 arguments. var a = myFunc \u0026#39;hello\u0026#39; (1 + 2 * 3) -- Nested function call using the shorthand convention. a = myFunc \u0026#39;hello\u0026#39; (otherFunc 1+2 \u0026#39;world\u0026#39;) The call expression block continues to add arguments from the block\u0026rsquo;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.\nPlanned Feature\nfoo(123): ..func (): return 123 param3: 123 234 bar() \u0026#39;hello\u0026#39; 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'.\n"},{"id":4,"href":"/cyber/docs/toc/modules/","title":"Modules","section":"Table of Contents","content":" Modules. # Modules have their own namespace and contain accessible static symbols. By default, importing another Cyber script returns a module with its declared symbols.\nImporting. # 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\u0026rsquo;s directory. An embedder can integrate their own module loader.\nimport t \u0026#39;test\u0026#39; t.eq(123, 123) -- Imports are static declarations so they can be anywhere in the script. import m \u0026#39;math\u0026#39; print m.cos(0) -- Loading another Cyber script. import foo \u0026#39;bar.cy\u0026#39; print foo.myFunc() print foo.myVar A Cyber script that is imported doesn\u0026rsquo;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.\n-- main.cy import a \u0026#39;foo.cy\u0026#39; print a.foo -- foo.cy import \u0026#39;bar.cy\u0026#39; var foo: 123 print foo -- Statement is ignored. -- bar.cy 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.\n-- main.cy import foo \u0026#39;foo.cy\u0026#39; func printB(): foo.printC() foo.printA() -- foo.cy import main \u0026#39;main.cy\u0026#39; func printA(): main.printB() func printC(): print \u0026#39;done\u0026#39; Static variable declarations from imports can have circular references. Read more about this in Static Variables.\nModules can also be destructured using the following syntax:\nimport { cos, pi } \u0026#39;math\u0026#39; print cos(pi) Exporting. # All static declarations are exported when the script\u0026rsquo;s module is loaded.\nfunc foo(): -- Exported static function. print 123 var bar: 234 -- Exported static variable. type Thing object: -- Exported type. a float The annotation @hide provides a hint to editors that the static symbol should not appear in the auto-complete. Despite this, the symbol is still reachable.\nPlanned Feature\nBuiltin Modules. # Cyber currently contains the builtin modules:\ncore: Cyber related functions and commonly used utilities. math: Math constants and functions. os: System level functions. test: Utilities for testing. Incomplete: The docs for builtins are not completely up-to-date. They will be auto generated in the future.\nCore Module. # The core module contains functions related to Cyber and common utilities. It is automatically imported into each script\u0026rsquo;s namespace.\nSample usage:\nprint \u0026#39;hello\u0026#39; var contents = readFile \u0026#39;foo.txt\u0026#39; print contents Function Summary arrayFill(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. boolean(val any) boolean Converts a value to either true or false. cacheUrl(url string) string Returns the path of a locally cached file of url. If no such file exists locally, it\u0026rsquo;s fetched from url. copy(val any) any Copies a primitive value or creates a shallow copy of an object value. error(e (enum | symbol)) error Create an error from an enum or symbol. execCmd(args []string) Map{ out, err, exited } Runs a shell command and returns the stdout/stderr. exit(status int) noreturn Exits the program with a status code. evalJS(val string) none Evals JS from the host environment. This is only available in a web WASM build of Cyber. fetchUrl(url string) rawstring Fetches the contents at url using the HTTP GET request method. getInput() rawstring Reads stdin until a new line is reached. This is intended to read user input from the command line. For bulk reads from stdin, use os.stdin. int(val any) int Converts a value to an 32-bit integer. isAlpha(val int) boolean Returns whether a rune is an alphabetic letter. isDigit(val int) boolean Returns whether a rune is a digit. must(val any) any | noreturn If val is an error, panic(val) is invoked. Otherwise, val is returned. float(val any) float Casts or converts the value to a float. Panics if type conversion fails. panic(e symbol) noreturn Stop execution in the current fiber and starts unwinding the call stack. See Unexpected Errors. parseCyber(src any) 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. parseCyon(src any) any Parses a CYON string into a value. performGC() map Runs the garbage collector once to detect reference cycles and abandoned objects. Returns the statistics of the run in a map value. pointer(val any) pointer Converts a int to a pointer value, or casts to a pointer. This is usually used with FFI. print(s string) none Prints a value as a string to stdout. The new line is also printed. prints(s string) none Prints a value as a string to stdout. rawstring(str string) rawstring Converts a string to a rawstring. readAll() rawstring Reads stdin to the EOF as a rawstring. readFile(path string) rawstring Reads the file contents into a rawstring value. runestr(val int) string Converts a rune to a string. string(val any) string Converts a value to a string. toCyon(val any) string Encodes a value to CYON string. typeof(any) metatype Returns the value\u0026rsquo;s type as a metatype object. typesym(any) symbol Returns the value\u0026rsquo;s type as one of the predefined symbols: #float, #int, #boolean, #object, #list, #map, #string, #rawstring, #function, #fiber, #pointer, #symbol, #metatype, #none, #error writeFile(path string, contents string) none Writes a string value to a file. Math Module. # The math module contains commonly used math constants and functions.\nSample usage:\nimport m \u0026#39;math\u0026#39; var r = 10 print(m.pi * r^2) Variable Type Summary e float Euler\u0026rsquo;s number and the base of natural logarithms; approximately 2.718. inf float Infinity. log10e float Base-10 logarithm of E; approximately 0.434. log2e float Base-2 logarithm of E; approximately 1.443. ln10 float Natural logarithm of 10; approximately 2.303. ln2 float Natural logarithm of 2; approximately 0.693. nan float Not a number. Note that nan == nan, however, if a nan came from an arithmetic operation, the comparison is undefined (it may be true or false, so it is not reliable). neginf float Negative infinity. pi float Ratio of a circle\u0026rsquo;s circumference to its diameter; approximately 3.14159. sqrt1_2 float Square root of ½; approximately 0.707. sqrt2 float Square root of 2; approximately 1.414. Function Summary abs(float) float Returns the absolute value of x. acos(float) float Returns the arccosine of x. acosh(float) float Returns the hyperbolic arccosine of x. asin(float) float Returns the arcsine of x. asinh(float) float Returns the hyperbolic arcsine of a number. atan(float) float Returns the arctangent of x. atan2(float, float) float Returns the arctangent of the quotient of its arguments. atanh(float) float Returns the hyperbolic arctangent of x. cbrt(float) float Returns the cube root of x. ceil(float) float Returns the smallest integer greater than or equal to x. clz32(float) float Returns the number of leading zero bits of the 32-bit integer x. cos(float) float Returns the cosine of x. cosh(float) float Returns the hyperbolic cosine of x. exp(float) float Returns e^x, where x is the argument, and e is Euler\u0026rsquo;s number (2.718…, the base of the natural logarithm). expm1(float) float Returns subtracting 1 from exp(x). floor(float) float Returns the largest integer less than or equal to x. hypot(float, float) float Returns the square root of the sum of squares of its arguments. isNaN(float) bool Returns whether x is not a number. ln(float) float Returns the natural logarithm (㏒e; also, ㏑) of x. log(float, float) float Returns the logarithm of y with base x. log10(float) float Returns the base-10 logarithm of x. log1p(float) float Returns the natural logarithm (㏒e; also ㏑) of 1 + x for the number x. log2(float) float Returns the base-2 logarithm of x. max(float, float) float Returns the largest of two numbers. min(float, float) float Returns the smallest of two numbers. mul32(float, float) float Returns the result of the 32-bit integer multiplication of x and y. Integer overflow is allowed. pow(float, float) float Returns base x to the exponent power y (that is, x^y). random() float Returns a pseudo-random number between 0 and 1. round(float) float Returns the value of the number x rounded to the nearest integer. sign(float) float Returns the sign of the x, indicating whether x is positive, negative, or zero. sin(float) float Returns the sine of x. sinh(float) float Returns the hyperbolic sine of x. sqrt(float) float Returns the positive square root of x. tan(float) float Returns the tangent of x. tanh(float) float Returns the hyperbolic tangent of x. trunc(float) float Returns the integer portion of x, removing any fractional digits. Os Module. # Cyber\u0026rsquo;s os module contains system level functions. It\u0026rsquo;s still undecided as to how much should be included here so it\u0026rsquo;s incomplete. You can still access os and libc functions yourself using Cyber\u0026rsquo;s FFI or embedding API.\nSample usage:\nimport os \u0026#39;os\u0026#39; var map = os.getEnvAll() for map each k, v: print \u0026#39;{k} -\u0026gt; {v}\u0026#39; Variable Type Summary cpu string The current cpu arch\u0026rsquo;s tag name. endian #little, #big The current arch\u0026rsquo;s endianness. stderr File Standard error file descriptor. stdin File Standard input file descriptor. stdout File Standard output file descriptor. system string The current operating system\u0026rsquo;s tag name. vecBitSize int Default SIMD vector bit size. Function Summary access(path any, mode (#read | #write | #readWrite)) true | error Attempts to access a file at the given path with the #read, #write, or #readWrite mode. Return true or an error. args() List\u0026lt;string | rawstring\u0026gt; Returns the command line arguments as a list. Each argument is validated and returned as a UTF-8 string or rawstring if the validation failed. bindLib(path any, decls [](CFunc|CStruct)) Object | Map Calls bindLib(path, decls, {}). bindLib(path any, decls [](CFunc|CStruct), config: BindLibConfig) Object | Map Creates an FFI binding to a dynamic library and it\u0026rsquo;s symbols. By default, an anonymous object is returned with the C-functions binded as the object\u0026rsquo;s methods. If config contains genMap: true, a Map is returned instead with C-functions binded as function values. copyFile(srcPath any, dstPath any) none | error Copies a file to a destination path. createDir(path any) true | error Creates the directory at path. Returns true if successful. createFile(path any, truncate boolean) File | error Creates and opens the file at path. If truncate is true, an existing file will be truncated. cstr(any) pointer Returns a null terminated C string. cwd() string Returns the current working directory. dirName(path any) string | none Returns the given path with its last component removed. exePath() string Returns the current executable\u0026rsquo;s path. free(ptr pointer) none Frees the memory located at ptr. fromCstr(pointer) rawstring Returns a rawstring from a null terminated C string. getEnv(key any) string | none Returns an environment value by key. getEnvAll() Map Returns all environment entries as a Map. malloc(size int) pointer Allocates size bytes of memory and returns a pointer. milliTime() float Return the calendar timestamp, in milliseconds, relative to UTC 1970-01-01. openDir(path any) Dir | error Invokes openDir(path, false). openDir(path any, iterable boolean) Dir | error Opens a directory at the given path. iterable indicates that the directory\u0026rsquo;s entries can be iterated. openFile(path any, mode (#read | #write | #readWrite)) File | error Opens a file at the given path with the #read, #write, or #readWrite mode. parseArgs(options list[ArgOption]) map Given expected ArgOptions, returns a map of the options and a rest entry which contains the non-option arguments. realPath(path any) string | error Returns the absolute path of the given path. removeDir(path any) true | error Removes an empty directory at path. Returns true if successful. removeFile(path any) true | error Removes the file at path. Returns true if successful. setEnv(key any, value any) none Sets an environment value by key. sleep(ms float) none Pauses the current thread for given milliseconds. unsetEnv(key any) none Removes an environment value by key. type File # Method Summary close() none Closes the file handle. File ops invoked afterwards will return error.Closed. read(n float) rawstring Reads at most n bytes as a rawstring. n must be at least 1. A result with length 0 indicates the end of file was reached. readToEnd() rawstring Reads to the end of the file and returns the content as a rawstring. seek(pos float) none Seeks the read/write position to pos bytes from the start. Negative pos is invalid. seekFromCur(pos float) none Seeks the read/write position by pos bytes from the current position. seekFromEnd(pos float) none Seeks the read/write position by pos bytes from the end. Positive pos is invalid. stat() Map Returns info about the file as a Map. streamLines() Iterable\u0026lt;rawstring\u0026gt; Equivalent to streamLines(4096). streamLines(bufSize float) Iterable\u0026lt;rawstring\u0026gt; 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. write(data (string | rawstring)) float Writes a string or rawstring at the current file position. The number of bytes written is returned. type Dir # Method Summary iterator() Iterator\u0026lt;DirEntry\u0026gt; | error Returns a new iterator over the directory entries. If this directory was not opened with the iterable flag, error.NotAllowed is returned instead. stat() Map Returns info about the file as a Map. walk() Iterator\u0026lt;DirWalkEntry\u0026gt; | error Returns a new iterator over the directory recursive entries. If this directory was not opened with the iterable flag, error.NotAllowed is returned instead. map DirEntry # Entry Summary 'name' -\u0026gt; rawstring The name of the file or directory. 'type' -\u0026gt; #file | #dir | #unknown The type of the entry. map DirWalkEntry # Entry Summary 'name' -\u0026gt; rawstring The name of the file or directory. 'path' -\u0026gt; rawstring The path of the file or directory relative to the walker\u0026rsquo;s root directory. 'type' -\u0026gt; #file | #dir | #unknown The type of the entry. map ArgOption # Entry Summary 'name' -\u0026gt; string The name of the option to match excluding the hyphen prefix. eg. -path 'type' -\u0026gt; metatype(string | float | boolean) Parse as given value type. 'default' -\u0026gt; any Optional: Default value if option is missing. none is used if this is not provided. Test Module. # The test module contains utilities for testing.\nSample usage:\nimport t \u0026#39;test\u0026#39; var a = 123 + 321 t.eq(a, 444) Function Summary eq(a any, b any) true | error Returns whether two values are equal. Returns error.AssertError if types do not match up. eqList(a any, b any) true | error Returns true if two lists have the same size and the elements are equal as if eq was called on those corresponding elements. eqNear(a any, b any) true | error Returns two numbers are near each other within epsilon 1e-5. "},{"id":5,"href":"/cyber/docs/toc/ffi/","title":"FFI","section":"Table of Contents","content":" FFI. # 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. bindLib is part of the os module and accepts the path to the library as a string and a list of CFunc or CStruct declarations.\nimport os \u0026#39;os\u0026#39; var lib = os.bindLib(\u0026#39;mylib.so\u0026#39;, [ os.CFunc{ sym: \u0026#39;add\u0026#39;, args: [#int, #int], ret: #int } ]) lib.add(123, 321) 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. \u0026lsquo;/foo/mylib.so\u0026rsquo;) or relative (eg. \u0026lsquo;./mylib.so\u0026rsquo;) 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 embedded Cyber app/runtime.\nWhen using CFunc or CStruct declarations, symbols are used to represent default type mappings from Cyber to C and back:\nIncomplete: 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.\nBinding Cyber C Details #bool bool bool #char float int8_t, signed char #uchar float uint8_t, unsigned char #short float int16_t, short #ushort float uint16_t, unsigned short #int float int32_t, int #uint float uint32_t, unsigned int #long float int64_t, long long #ulong float uint64_t, unsigned long long #usize float size_t, uintptr_t #float float float #double float double #charPtr pointer char* Use os.cstr() and os.fromCstr() to convert between a Cyber string and a null terminated C string. #voidPtr pointer void* sym symbol object \u0026lt;sym\u0026gt; Struct The mapping from a Cyber object type sym and the C-struct can be declared with CStruct. By default bindLib returns an anonymous object with the binded C-functions as methods. This is convenient for using it like an object, but it\u0026rsquo;s less optimal compared to binding as functions. If a config is passed into bindLib as the third argument, genMap: true makes bindLib return a map instead with the binded C-functions as Cyber functions. 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.\nCFunc. # The CFunc object lets you bind to a C-function. The sym field maps to the C-function\u0026rsquo;s symbol name in the dynamic library. The args field declares the type mapping from Cyber to C-function\u0026rsquo;s arguments. Finally, the ret field declares the type mapping from the C-function\u0026rsquo;s return type to a Cyber type.\nimport os \u0026#39;os\u0026#39; var lib = os.bindLib(\u0026#39;mylib.so\u0026#39;, [ os.CFunc{ sym: \u0026#39;add\u0026#39;, args: [#int, #int], ret: #int } ]) lib.add(123, 321) The example above maps to this C declaration in mylib.so:\nint add(int a, int b) { return a + b; } CStruct. # You can also bind object types to C-structs using the CStruct object. The type field accepts an object type symbol and fields indicates the mapping for each field in type to and from a C-struct. After adding a CStruct declaration, you can use the object type symbol in CFunc args and ret and also other CStruct fields.\nimport os \u0026#39;os\u0026#39; type MyObject object: a float b pointer c bool var lib = os.bindLib(\u0026#39;mylib.so\u0026#39;, [ os.CFunc{ sym: \u0026#39;foo\u0026#39;, args: [MyObject], ret: MyObject } os.CStruct{ fields: [#f64, #charPtr, #bool], type: MyObject } ]) var res = lib.foo(MyObject{ a: 123, b: os.cstr(\u0026#39;foo\u0026#39;), c: true }) The example above maps to these C declarations in mylib.so:\ntypedef struct MyObject { double a; char* b; bool c; } MyObject; MyObject foo(MyObject o) { // Do something. } CStruct also generates ptrTo[Type] as a helper function to dereference an opaque ptr to a new Cyber object:\nimport os \u0026#39;os\u0026#39; var lib = os.bindLib(\u0026#39;mylib.so\u0026#39;, [ os.CFunc{ sym: \u0026#39;foo\u0026#39;, args: [MyObject], ret: #voidPtr } os.CStruct{ fields: [#f64, #charPtr, #bool], type: MyObject } ]) var ptr = lib.foo(MyObject{ a: 123, b: os.cstr(\u0026#39;foo\u0026#39;), c: true }) var res = lib.ptrToMyObject(ptr) Pointers # A pointer is used to read or write to an exact memory address. This is typically used for FFI to manually map Cyber types to C, and back. A new pointer can be created with the builtin pointer.\nvar ptr = pointer(0xDEADBEEF) print ptr.value() --\u0026#39;3735928559\u0026#39; type pointer # Method Summary value() int Returns the memory address as an int. The value may be negative since it\u0026rsquo;s bitcasted from an unsigned 48-bit integer but it retains the original pointer bits. "},{"id":6,"href":"/cyber/docs/toc/errors/","title":"Error Handling","section":"Table of Contents","content":" Error Handling. # Cyber provides error values and try/catch mechanisms to handle expected errors. For unexpected errors, panics can be used as a fail-fast mechanism to abort the currently running fiber.\nError value. # The error type is a primitive that contains either an enum value or a symbol value. Errors can wrap symbols for convenience but the underlying ID value won\u0026rsquo;t be consistent. Use your own enums if you want reliable ID values.\n-- Shorthand for creating an error value with a symbol. var err = error.Oops -- Alternatively, use the builtin error function to wrap a symbol. err = error(#Oops) type MyError enum: boom badArgument nameTooLong -- Creates an error that wraps an enum value. err = error(MyError.boom) You can attach an optional payload value to an error.\nPlanned Feature\nSince errors are primitives, they can be compared using the == operator.\nif err == error.Oops: handleOops() -- Alternatively. if err.value() == #Oops: handleOops() -- Comparing errors with enums. if err == error(MyError.boom) handleBoom() -- Alternatively. if err.value() == MyError.boom handleBoom() Throwing errors. # 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.\nfunc fail(): throw error.Oops -- Throws an error with the symbol `#Oops` func fail2(): throw 123 -- Panic, Can only throw errors. throw can also be used as an expression.\nfunc fail(): var a = false or throw error.False Catching errors. # The try catch block catches thrown errors and resumes execution in the catch block.\ntry: funcThatCanFail() catch err: print err -- \u0026#39;error.Failed\u0026#39; The try else expression either returns a non-error result or the default value from the else clause.\nvar res = try funcThatCanFail() else 123 print res -- \u0026#39;123\u0026#39; -- Any errors thrown from sub expressions also return the default value. res = try happyFunc(funcThatCanFail()) else 123 print res -- \u0026#39;123\u0026#39; When try is used by itself, either the result or the caught error value is returned.\nvar res = try funcThatCanFail() if res == error.Failed: print \u0026#39;Result is an error.\u0026#39; -- Any errors thrown from sub expressions are also caught. res = try happyFunc(funcThatCanFail()) Stack trace. # When an uncaught error bubbles up to the top, its stack trace from the throw callsite is dumped to the console. Cyber also provides the builtin errorTrace() and errorReport() to obtain the stack trace info.\ntry: funcThatCanFail() catch err: -- Prints the stack trace summary of the caught error. print errorReport() -- Provides structured info about the stack trace. var info = errorTrace() print info.frames.len() Unexpected errors. # An unexpected error is an error that you don\u0026rsquo;t plan on handling at runtime. In this scenario, you can prefer to fail-fast and panic.\nPanics can not be caught using try catch. Once the builtin 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 can resume on the next fiber which allows you to recover from a panic.\nfunc kaboom(): panic(#danger) kaboom() -- Script ends and prints the stack trace. "},{"id":7,"href":"/cyber/docs/toc/concurrency/","title":"Concurrency","section":"Table of Contents","content":" Concurrency. # Cyber supports fibers as a concurrency mechanism. There are plans to support preemptive concurrency with async/await as well as multithreading.\nFibers. # Fibers in Cyber allow representing execution contexts as first-class values. They contain their own call stack and program counters. Fibers by themselves do not enable parallelism.\nThe coinit creates a new fiber from a function call syntax. Using coyield inside a function pauses the current fiber and execution is returned to the fiber that invoked coresume.\nvar count = 0 var foo = func (): count += 1 coyield count += 1 var fiber = coinit foo() print count -- \u0026#39;0\u0026#39; coresume fiber print count -- \u0026#39;1\u0026#39; coresume fiber print count -- \u0026#39;2\u0026#39; In Cyber, coyield can be used anywhere in a fiber\u0026rsquo;s call stack.\nfunc foo(): print \u0026#39;foo\u0026#39; bar() func bar(): -- Nested coyield in call stack. coyield print \u0026#39;bar\u0026#39; var fiber = coinit foo() coresume fiber coresume also returns the resulting value.\nfunc foo(): return 123 var fiber = coinit foo() print(coresume fiber) -- \u0026#39;123\u0026#39; coyield can return a value back to coresume.\nPlanned Feature\nUse Fiber.status() to get the current state of the fiber.\nfunc foo(): coyield print \u0026#39;done\u0026#39; var fiber = coinit foo() print fiber.status() -- \u0026#39;#paused\u0026#39; coresume fiber print fiber.status() -- \u0026#39;#paused\u0026#39; coresume fiber print fiber.status() -- \u0026#39;#done\u0026#39; 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.\nGas mileage. # Planned Feature\nAsync. # Planned Feature\nMulti-thread. # Planned Feature\n"},{"id":8,"href":"/cyber/docs/toc/type-system/","title":"Type System","section":"Table of Contents","content":" Type System. # Cyber supports gradual typing which allows the use of both dynamically and statically typed code.\nIncomplete: Types in general is in development. One of the goals of Cyber is to let dynamic code mix with typed code. At the moment, there are places where it works and other places where it won\u0026rsquo;t. Keep that in mind when using types.\nDynamic typing can reduce the amount of friction when writing code, but it can also result in more runtime errors. Gradual typing allows you to add static typing incrementally which provides compile-time guarantees and prevents runtime errors. Static typing also makes it easier to maintain and refactor your code.\nDynamic typing. # A variable with the any type can hold any value. It can only be copied to destinations that also accept the any type. An any value can be used as the callee for a function call or the receiver for a method call. It can be used with any operators.\nCompile-time dynamic typing. # Cyber introduces the concept of compile-time dynamic typing. This allows a local variable to gain additional compile-time features while using it as a dynamic value. It can prevent inevitable runtime errors and avoid unnecessary type casts.\nLocal variables declared without a type specifier start off with the type of their initializer. In the following, a is implicity declared as a float at compile-time because numeric literals default to the float type.\nvar a = 123 The type can change at compile-time from another assignment. If a is then assigned to a string literal, a from that point on becomes the string type at compile-time.\nvar a = 123 foo(a) -- Valid call expression. a = \u0026#39;hello\u0026#39; foo(a) -- CompileError. Expected `float` argument, got `string`. func foo(n float): pass The type of a can also change in branches. However, after the branch block, a will have a merged type determined by the types assigned to a from the two branched code paths. Currently, the any type is used if the types from the two branches differ. At the end of the following if block, a assumes the any type after merging the float and string types.\nvar a = 123 if a \u0026gt; 20: a = \u0026#39;hello\u0026#39; foo(a) -- Valid call expression. `foo` can be called without type casting. foo(a) -- CompileError. Expected `string` argument, got `any`. func foo(s string): pass Default types. # Static variables without a type specifier will always default to the any type. In the following, a is compiled with the any type despite being initialized to a numeric literal.\nvar a: 123 a = \u0026#39;hello\u0026#39; Function parameters without a type specifier will default to the any type. The return type also defaults to any. In the following, both a and b have the any type despite being only used for arithmetic.\nfunc add(a, b): return a + b print add(3, 4) Static typing. # In Cyber, types can be optionally declared with variables, parameters, and return values. The following builtin types are available in every namespace: bool, float, int, string, List, Map, error, fiber, any.\nA type object declaration creates a new object type.\ntype Student object: -- Creates a new type named `Student` name string age int gpa float When a type specifier follows a variable name, it declares the variable with the type. Any operation afterwards that violates the type constraint will result in a compile error.\nIncomplete: Only function parameter and object member type specifiers have meaning to the VM at the moment. Variable type specifiers have no meaning and will be discarded.\na float = 123 a = \u0026#39;hello\u0026#39; -- CompileError. Type mismatch. Parameter and return type specifiers in a function signature follows the same syntax.\nfunc mul(a float, b float) float: return a * b print mul(3, 4) print mul(3, \u0026#39;4\u0026#39;) -- CompileError. Function signature mismatch. Type specifiers must be resolved at compile-time.\ntype Foo object: a float b string c Bar -- CompileError. Bar is not declared. Circular type references are allowed.\ntype Node object: val any next Node -- Valid type specifier. Union types. # Planned Feature\nInterfaces. # Planned Feature\nType aliases. # A type alias is declared from a single line type statement. This creates a new type symbol for an existing data type.\nimport util \u0026#39;./util.cy\u0026#39; type Vec3 util.Vec3 var v = Vec3{ x: 3, y: 4, z: 5 } Type casting. # 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. If the cast fails at runtime, a panic is returned.\nprint(\u0026#39;123\u0026#39; as float) -- CompileError. Can not cast `string` to `float`. erased any = 123 add(1, erased as float) -- Success. print(erased as string) -- Panic. Can not cast `float` to `string`. func add(a float, b float): return a + b Runtime type checking. # Since Cyber allows invoking any function values, the callee\u0026rsquo;s function signature is not always known at compile-time. To ensure type safety in this situation, type checking is done at runtime and with no additional overhead compared to calling an untyped function.\nop any = add print op(1, 2) -- \u0026#39;3\u0026#39; print op(1, \u0026#39;2\u0026#39;) -- Panic. Function signature mismatch. func add(a float, b float) float: return a + b "},{"id":9,"href":"/cyber/docs/toc/metaprogramming/","title":"Metaprogramming","section":"Table of Contents","content":" Metaprogramming. # Operator overloading. # All operators are implemented as object methods.\nIncomplete: Not all operators have transitioned to the method paradigm.\nNormally this would impact performance, but Cyber\u0026rsquo;s compiler generates specialized bytecode ops for builtin types like int and float. The VM performs inline caching at runtime to eliminate the overhead of evaluating operators on dynamic operands.\nTo overload an operator for a object type, declare $prefix, $infix, $postfix methods:\nIncomplete: Although operator overloading is supported in the VM and builtin types use it, it is not currently enabled for user types.\ntype Vec2 object: x float y float func $infix+(self, o): return Vec2{ x: x + o.x, y: y + o.y, } func $prefix-(self): return Vec2{ x: -x, y: -y } var a = Vec2{ x: 1, y: 2} var b = a + Vec2{ x: 3, y: 4 } var c = -a Some special operators have their own name:\ntype MyCollection object: arr List func $index(self, idx): return arr[idx * 2] func $setIndex(self, idx, val): arr[idx * 2] = val var a = MyCollection{ arr: [1, 2, 3, 4] } print a[1] -- Prints `3` A list of all supported operators:\n$prefix~(_) $prefix-(_) $infix\u0026gt;(_, _) $infix\u0026gt;=(_, _) $infix\u0026lt;(_, _) $infix\u0026lt;=(_, _) $infix+(_, _) $infix-(_, _) $infix*(_, _) $infix/(_, _) $infix%(_, _) $infix^(_, _) $infix\u0026amp;(_, _) $infix|(_, _) $infix||(_, _) $infix\u0026lt;\u0026lt;(_, _) $infix\u0026gt;\u0026gt;(_, _) $index(_, _) $setIndex(_, _, _) $slice(_, _, _) Custom operators. # Planned Feature\nMagic functions. # Call module. # Declare a $call function to allow invoking a module as a function.\nIncomplete: Although $call function is supported in the VM and builtin modules use it, it is not currently enabled for user modules.\n-- Object types are also modules. type Vec2 object: x float y float func $call(x float, y float) Vec2: return Vec2{ x: x, y: y } var v = Vec2(1, 2) Getter/Setter. # Planned Feature\nMissing method. # Declare a $missing method as a fallback when a method was not found in an instance.\nPlanned Feature\ntype A object: func $missing(self, args...): return args.len var a = A{}; print a.foo() -- Output: \u0026#39;0\u0026#39; print a.bar(1, 2) -- Output: \u0026#39;2\u0026#39; Reflection. # A metatype object references an internal type. Use the typeof builtin to get the metatype of a value.\nvar val = 123 print typeof(val) -- \u0026#39;type: float\u0026#39; -- Referencing a type as a value also returns its `metatype`. print boolean -- \u0026#39;type: boolean\u0026#39; type metatype # func id(self) int -- Returns the type ID as an `int`. Annotations. # Planned Feature\nRuntime eval. # Planned Feature\nGenerics. # Planned Feature\nCompile-time. # Planned Feature\n"},{"id":10,"href":"/cyber/docs/toc/embedding/","title":"Embedding","section":"Table of Contents","content":" Embedding. # Planned Feature\n"},{"id":11,"href":"/cyber/docs/toc/memory/","title":"Memory","section":"Table of Contents","content":" Memory. # Cyber provides memory safety by default.\nARC. # 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\u0026rsquo;s very own Cycle Detection.\nReference Counting. # In Cyber, there are primitive and object values. Primitives don\u0026rsquo;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).\nObject are managed by ARC and 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\u0026rsquo;s retained and the reference count increments by 1. When an object value is removed from it\u0026rsquo;s parent or is no longer reachable in the current stack frame, it is released and the reference count decrements by 1.\nOnce the reference count reaches 0 and the object (eg. List or Map) also contains child references, each child reference is released thereby decrementing their reference counts by 1. Afterwards, the object is freed from memory.\nOptimizations. # 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.\nClosures. # 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.\nFibers. # Fibers are freed by ARC just like any other object. Once there are no references to the fiber, it begins to release it\u0026rsquo;s child references by unwinding it\u0026rsquo;s call stack.\nHeap. # 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.\nWeak References. # Planned Feature\nCycle Detection. # 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.\nIncomplete Feature: Only the main fiber stack is cleaned up at the moment.\nTo invoke the GC, call the builtin function: performGC.\nfunc foo(): -- Create a reference cycle. var a = [] var b = [] a.append(b) b.append(a) var res = performGC() -- Cycle still alive in the current stack so no cleanup is done. print res[\u0026#39;numCycFreed\u0026#39;] -- Output: 0 print res[\u0026#39;numObjFreed\u0026#39;] -- Output: 0 foo() var res = performGC() -- `a` and `b` are no longer reachable, so the GC does work. print res[\u0026#39;numCycFreed\u0026#39;] -- Output: 2 print res[\u0026#39;numObjFreed\u0026#39;] -- Output: 2 "},{"id":12,"href":"/cyber/docs/toc/aot-jit/","title":"AOT/JIT","section":"Table of Contents","content":" AOT and JIT # Planned Feature\n"}] \ No newline at end of file diff --git a/en.search-data.min.fcf6482b69d03bc62a33db6550710b275db6444d7746b904b7478ba4f6d1db4f.json b/en.search-data.min.fcf6482b69d03bc62a33db6550710b275db6444d7746b904b7478ba4f6d1db4f.json deleted file mode 100644 index 9cf9f65d5..000000000 --- a/en.search-data.min.fcf6482b69d03bc62a33db6550710b275db6444d7746b904b7478ba4f6d1db4f.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":0,"href":"/cyber/docs/toc/syntax/","title":"Syntax","section":"Table of Contents","content":" Syntax # Cyber\u0026rsquo;s syntax is concise and easy to read.\nStatements. # A statement ends with the new line.\n-- An assignment statement. var a = 123 Blocks. # A new block starts with a colon. This is intended to give structure to nested statements without an ending delimiter.\n-- This `if` statement begins a new block. if true: var a = 234 The first statement in a block must be indented further. Spaces or tabs can be used for indentation but not both. Subsequent statements in the block must follow the same indentation. The block ends when a statement recedes from this indentation.\nfor items each it: if it == 20: print it 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.\n-- 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. print 234 Variables. # In Cyber, there are local variables and static variables.\nLocal Variables. # Local variables exist until the end of their scope. They are declared and initialized using the var keyword.\n-- Declaration. var a = 123 -- Subsequent assignment. a = 234 A new variable can be declared in function blocks with the same name as a variable from a parent block.\nvar a = 123 foo = func(): -- A new local `a` inside function `foo`. var a = 234 foo() print a -- \u0026#39;123\u0026#39; However, variables declared in sub-blocks such as if and for can not shadow variables in the same main/function block.\nvar a = 123 if true: -- CompileError, `a` is already declared in the main block. var a = 234 When a parent local is referenced in a lambda function, the variable is automatically captured. Note that static functions can not capture parent locals.\nIncomplete: Only variables one parent block away can be captured.\nvar a = 123 var foo = func(): a = 234 foo() print a -- \u0026#39;234\u0026#39; Static Variables. # Static variables live until the end of the script. They act as global variables and are visible from anywhere in the script.\nStatic variables are also declared with var but : is used instead of = to initialize a value to them.\nvar a: 123 func foo(): print a -- \u0026#39;123\u0026#39; Static variables are always exported from the current script. You can read more about exports and Modules.\nWhen declared in functions, static variables are initialized once and continue to exist for subsequent function calls.\nPlanned Feature\nfunc add(a): var sum: 0 sum += a return sum print add(5) -- \u0026#39;5\u0026#39; print add(5) -- \u0026#39;10\u0026#39; Since static variable declarations are initialized outside of a fiber\u0026rsquo;s execution flow, they can not reference any local variables.\nvar a = 123 var b: a -- Compile error, initializer can not reference a local variable. However, you can reassign any value to them with an assignment statement.\nvar a = 123 var b: 0 b = a -- Reassigning can reference a local variable. 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. The following would print \u0026lsquo;123\u0026rsquo; before \u0026lsquo;234\u0026rsquo;\nvar 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.\nvar a: b + 321 var b: 123 print a -- \u0026#39;444\u0026#39; Circular references in initializers are allowed. When initialization encounters a reference that creates this circular dependency, that reference evaluates to none. In the following, a attempts to initialize first because of its natural ordering. Since b is a dependency, it supersedes the natural ordering. When b is found to reference an already visited a (causing the circular dependency), it evaluatues to a\u0026rsquo;s current value which is none. At the end of initialization, both a and b have the value none.\nvar a: b var b: a 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.\nPlanned Feature\nvar myImage: var img = loadImage(\u0026#39;me.png\u0026#39;) 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.\nKeywords. # There are currently 33 keywords in Cyber. This list categorizes them and shows you when you might need them.\nControl Flow: if then else match while for each break continue pass some Operators: or and not is Variables: var as Functions: func return Coroutines: coinit coyield, coresume Data Types: type object enum true false none Error Handling: try catch error throw Modules: import Operators. # Cyber supports the following operators. They are ordered from highest to lowest precedence.\nOperator Description \u0026lt;\u0026lt; \u0026gt;\u0026gt; Bitwise left shift, right shift. \u0026amp; Bitwise and. | || Bitwise or, exclusive or. ^ Power. / % * Division, modulus, multiplication. + - Addition, subtraction. as Type casting. \u0026gt; \u0026gt;= \u0026lt; \u0026lt;= != == Greater, greater or equal, less, less or equal, not equals, equals. and Logical and. or Logical or. Arithmetic Operators. # The following arithmetic operators are supported for the numeric data types.\n1 + 2 -- Addition, evaluates to 3. 100 - 10 -- Subtraction, evaluates to 90. 3 * 4 -- Multiplication, evaluates to 12. 20 / 5 -- Division, evaluates to 4. 2 ^ 4 -- Raise to the power, evaluates to 16. 12 % 5 -- Modulus remainder, evaluates to 2. -(10) -- Apply negative, evaluates to -10. Comparison Operators. # Cyber supports the following comparison operators. By default, a comparison operator evaluates to a Boolean value.\nThe 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.\n1 == 1 -- Evaluates to `true` 1 == 2 -- Evaluates to `false` 1 == true -- Evaluates to `false` var a = \u0026#39;abc\u0026#39; a == \u0026#39;abc\u0026#39; -- Evaluates to `true` a = [] b = a a == b -- Evaluates to `true` a == [] -- Evaluates to `false` The not equals operator returns true if the two values are not equal.\n1 != 1 -- Evaluates to `false` 1 != 2 -- Evaluates to `true` Number types have additional comparison operators.\na \u0026gt; b -- `true` if a is greater than b a \u0026gt;= b -- `true` if a is greater than or equal to b a \u0026lt; b -- `true` if a is less than b a \u0026lt;= b -- `true` if a is less than or equal to b Logic Operators. # The logical operators and, or, and not are supported.\nand 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\u0026rsquo;t 0 is truthy. An object reference is always truthy. The none value is not truthy.\ntrue 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.\ntrue 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.\nnot false -- Evaluates to true not true -- Evaluates to false not 0 -- Evaluates to true not 123 -- Evaluates to false !false -- Evaluates to true !true -- Evaluates to false Bitwise Operators. # The following bitwise operators are supported for int number values.\n-- Bitwise and: any underlying bits that are set in both integers are set in the new integer. a \u0026amp; b -- Bitwise or: any underlying bits that are set in either integer a or integer b are set in the new integer. a | b -- Bitwise exclusive or: any underlying bits that are set in either integer a or integer b but not both are set in the new integer. a || b -- Bitwise right shift: a\u0026#39;s bits are shifted b bits to the least significant end. This performs sign-extension on the 32-bit integer. a \u0026gt;\u0026gt; b -- Bitwise left shift: a\u0026#39;s bits are shifted b bits to the most significant end. This does not perform sign-extension on the 32-bit integer. a \u0026lt;\u0026lt; b -- Bitwise not: a\u0026#39;s integer bits are flipped. ~a Operator Overloading. # See Operator Overloading in Metaprogramming.\nComments. # A single line comment starts with two hyphens and ends at the end of the line.\n-- 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.\nCYON. # CYON or the Cyber object notation is similar to JSON. The format uses the same literal value semantics as Cyber.\n{ name: \u0026#39;John Doe\u0026#39; \u0026#39;age\u0026#39;: 25 -- This is a comment cities: [ \u0026#39;New York\u0026#39; \u0026#39;San Francisco\u0026#39; \u0026#39;Tokyo\u0026#39; ] } "},{"id":1,"href":"/cyber/docs/toc/data-types/","title":"Data Types","section":"Table of Contents","content":" Data Types. # In Cyber, there are primitive types and object types. Primitives are copied around by value and don\u0026rsquo;t need additional heap memory or reference counts. Primitives include Booleans, Floats, Integers, Enums, Symbols, Errors, Static Strings, and the none value. Object types include Lists, Maps, Strings, Custom Objects, Lambdas, Fibers, Errors with payloads, Pointers, and several internal object types.\nThe none value represents an empty value. This is similar to null in other languages.\nBooleans. # Booleans can be true or false.\nvar a = true if a: print \u0026#39;a is true\u0026#39; When other value types are coerced to the boolean type, the truthy value is determined as follows.\nThe none value is false. Other objects and values are always true. Numbers. # Integers. # int is the default integer type. It has 48-bits and can represent integers in the range -(247) to 247-1.\nWhen a numeric literal is used and the type can not be inferred, it will default to the int type:\nvar a = 123 Integer notations always produce a int value:\nvar a = 0xFF -- hex. a = 0o17 -- octal. a = 0b1010 -- binary. a = 0u\u0026#39;🐶\u0026#39; -- UTF-8 rune. Arbitrary values can be converted to a int using the type as a function.\nvar a = \u0026#39;123\u0026#39; var b = int(a) In addition to arithmetic operations, integers can also perform bitwise operations.\nFloats. # float is the default floating point type. It has a (IEEE 754) 64-bit floating point format.\nAlthough 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.\nA numeric literal can be used to create a float if the inferred type is a float:\na float = 123 Decimal and scientific notations always produce a float value:\nvar a = 2.34567 var b = 123.0e4 Arbitrary values can be converted to a float using the type as a function.\nvar a = \u0026#39;12.3\u0026#39; var b = float(a) Big Numbers. # Planned Feature\nStrings. # 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. Under the hood, Cyber implements 6 different internal string types to optimize string operations, but the user just sees them as one type and doesn\u0026rsquo;t need to care about this detail under normal usage.\nStrings 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 the StringBuffer.\nPlanned Feature\nA string is always UTF-8 validated. rawstrings outperform strings but you\u0026rsquo;ll have to validate them and take care of indexing yourself.\nA single line string literal is surrounded in single quotes.\nvar apple = \u0026#39;a fruit\u0026#39; You can escape the single quote inside the literal or use double quotes.\nvar apple = \u0026#39;Bob\\\u0026#39;s fruit\u0026#39; apple = \u0026#34;Bob\u0026#39;s fruit\u0026#34; Strings are UTF-8 encoded.\nvar str = \u0026#39;abc🦊xyz🐶\u0026#39; Use double quotes to surround a multi-line string.\nvar str = \u0026#34;line a line b line c\u0026#34; You can escape double quotes inside the literal or use triple quotes.\nvar str = \u0026#34;line a line \\\u0026#34;b\\\u0026#34; line c\u0026#34; -- Using triple quotes. str = \u0026#39;\u0026#39;\u0026#39;line a line \u0026#34;b\u0026#34; line c \u0026#39;\u0026#39;\u0026#39; The following escape sequences are supported:\nEscape Sequence Code Description \\a 0x07 Terminal bell. \\b 0x08 Backspace. \\e 0x1b Escape character. \\n 0x0a Line feed character. \\r 0x0d Carriage return character. \\t 0x09 Horizontal tab character. The boundary of each line can be set with a vertical line character. This makes it easier to see the whitespace.\nvar poem = \u0026#34;line a | two spaces from the left | indented further\u0026#34; 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().\nvar str = \u0026#39;abcd\u0026#39; print str[1] -- \u0026#34;b\u0026#34; print str[-1] -- \u0026#34;d\u0026#34; Using the slice index 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\u0026rsquo;s length.\nvar str = \u0026#39;abcxyz\u0026#39; var sub = str[0..3] print sub -- \u0026#34;abc\u0026#34; print str[..5] -- \u0026#34;abcxy\u0026#34; print str[1..] -- \u0026#34;bcxyz\u0026#34; -- One way to use slices is to continue a string operation. str = \u0026#39;abcabcabc\u0026#39; var i = str.findRune(0u\u0026#39;c\u0026#39;) print(i) -- \u0026#34;2\u0026#34; i += 1 print(i + str[i..].findRune(0u\u0026#39;c\u0026#39;)) -- \u0026#34;5\u0026#34; type string # func concat(self, str string) string -- Returns a new string that concats this string and `str`. func endsWith(self, suffix string) bool -- Returns whether the string ends with `suffix`. func find(self, needle string) int? -- Returns the first index of substring `needle` in the string or `none` if not found. func findAnyRune(self, set string) int? -- Returns the first index of any UTF-8 rune in `set` or `none` if not found. func findRune(self, needle int) int? -- Returns the first index of UTF-8 rune `needle` in the string or `none` if not found. func insert(self, idx int, str string) string -- Returns a new string with `str` inserted at index `idx`. func isAscii(self) bool -- Returns whether the string contains all ASCII runes. func len(self) int -- Returns the number of UTF-8 runes in the string. func less(self, str string) bool -- Returns whether this string is lexicographically before `str`. func lower(self) string -- Returns this string in lowercase. func replace(self, needle string, replacement string) string -- Returns a new string with all occurrences of `needle` replaced with `replacement`. | func repeat(self, n int) string -- Returns a new string with this string repeated `n` times. func runeAt(self, idx int) int -- Returns the UTF-8 rune at index `idx`. func slice(self, start int, end int) string -- Returns a slice into this string from `start` to `end` (exclusive) indexes. This is equivalent to using the slice index operator `[start..end]`. func sliceAt(self, idx int) string -- Returns the UTF-8 rune at index `idx` as a single rune string. func split(self, delim string) List -- Returns a list of UTF-8 strings split at occurrences of `delim`. func startsWith(self, prefix string) bool -- Returns whether the string starts with `prefix`. func trim(self, mode symbol, trimRunes any) string -- Returns the string with ends trimmed from runes in `trimRunes`. `mode` can be #left, #right, or #ends. func upper(self) string -- Returns this string in uppercase. String Interpolation. # You can embed expressions into string templates using braces.\nvar name = \u0026#39;Bob\u0026#39; var points = 123 var str = \u0026#39;Scoreboard: {name} {points}\u0026#39; Escape braces with a backslash.\nvar points = 123 var str = \u0026#39;Scoreboard: \\{ Bob \\} {points}\u0026#39; String templates can not contain nested string templates.\nrawstring. # A rawstring does not automatically validate the string and is indexed by bytes and not UTF-8 runes.\nUsing the index operator will return the UTF-8 rune starting at the given byte index as a slice. If the index does not begin a valid UTF-8 rune, error.InvalidRune is returned. This is equivalent to calling the method sliceAt().\nvar str = rawstring(\u0026#39;abcd\u0026#39;).insertByte(1, 255) print str[0] -- \u0026#34;a\u0026#34; print str[1] -- error.InvalidRune print str[-1] -- \u0026#34;d\u0026#34; type rawstring # func byteAt(self, idx int) int -- Returns the byte value (0-255) at the given index `idx`. func concat(self, str string) string -- Returns a new string that concats this string and `str`. func endsWith(self, suffix string) bool -- Returns whether the string ends with `suffix`. func find(self, needle string) int? -- Returns the first index of substring `needle` in the string or `none` if not found. func findAnyRune(self, set string) int? -- Returns the first index of any UTF-8 rune in `set` or `none` if not found. func findRune(self, needle int) int? -- Returns the first index of UTF-8 rune `needle` in the string or `none` if not found. func insert(self, idx int, str string) string -- Returns a new string with `str` inserted at index `idx`. func insertByte(self, idx int, byte int) string -- Returns a new string with `byte` inserted at index `idx`. func isAscii(self) bool -- Returns whether the string contains all ASCII runes. func len(self) int -- Returns the number of bytes in the string. func less(self, str rawstring) bool -- Returns whether this rawstring is lexicographically before `str`. func lower(self) string -- Returns this string in lowercase. func repeat(self, n int) rawstring -- Returns a new rawstring with this rawstring repeated `n` times. func replace(self, needle string, replacement string) string -- Returns a new string with all occurrences of `needle` replaced with `replacement`. func runeAt(self, idx int) int -- Returns the UTF-8 rune at index `idx`. If the index does not begin a UTF-8 rune, `error.InvalidRune` is returned. func slice(self, start int, end int) rawstring -- Returns a slice into this string from `start` to `end` (exclusive) indexes. This is equivalent to using the slice index operator `[start..end]`. func sliceAt(self, idx int) string -- Returns the UTF-8 rune at index `idx` as a single rune string. If the index does not begin a UTF-8 rune, `error.InvalidRune` is returned. func split(self, delim string) List -- Returns a list of rawstrings split at occurrences of `delim`. func startsWith(self, prefix string) bool -- Returns whether the string starts with `prefix`. func upper(self) string -- Returns this string in uppercase. func trim(self, mode symbol, trimRunes any) rawstring -- Returns the string with ends trimmed from runes in `trimRunes`. `mode` can be #left, #right, or #ends. func utf8(self) string -- Returns a valid UTF-8 string or returns `error.InvalidRune`. Lists. # Lists are a builtin type that holds an ordered collection of elements. Lists grow or shrink as you insert or remove elements.\n-- Construct a new list. var list = [1, 2, 3] -- The first element of the list starts at index 0. print list[0] -- Prints \u0026#39;1\u0026#39; -- Using a negative index starts at the back of the list. print list[-1] -- Prints \u0026#39;3\u0026#39; 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. Negative start or end values count from the end of the list.\nvar list = [ 1, 2, 3, 4, 5 ] list[0..0] -- [] Empty list. list[0..3] -- [ 1, 2, 3 ] From start to end index. list[3..] -- [ 4, 5 ] From start index to end of list. list[..3] -- [ 1, 2, 3 ] From start of list to end index. list[2..+2] -- [ 3, 4 ] From start index to start index + amount. List operations.\nvar list = [234] -- Append a value. list.append 123 print list[-1] -- Prints \u0026#39;123\u0026#39; -- Inserting a value at an index. list.insert(1, 345) -- Get the length. print list.len() -- Prints \u0026#39;2\u0026#39; -- Sort the list in place. list.sort((a, b) =\u0026gt; a \u0026lt; b) -- Iterating a list. for list each it: print it -- Remove an element at a specific index. list.remove(1) type List # Method Summary append(val any) none Appends a value to the end of the list. concat(val any) none Concats the elements of another list to the end of this list. insert(idx int, val any) none Inserts a value at index idx. iterator() Iterator\u0026lt;any\u0026gt; Returns a new iterator over the list elements. joinString(separator any) string Returns a new string that joins the elements with separator. len() int Returns the number of elements in the list. pairIterator() PairIterator\u0026lt;int, any\u0026gt; Returns a new pair iterator over the list elements. remove(idx int) none Removes an element at index idx. resize(len int) none Resizes the list to len elements. If the new size is bigger, none values are appended to the list. If the new size is smaller, elements at the end of the list are removed. sort(less func (a, b) bool) none Sorts the list with the given less function. If element a should be ordered before b, the function should return true otherwise false. Maps. # Maps are a builtin type that store key value pairs in dictionaries.\nvar map = { a: 123, b: () =\u0026gt; 5 } print map[\u0026#39;a\u0026#39;] -- You can also access the map using an access expression. print map.a -- Map entries can be separated by the new line. map = { foo: 1 bar: 2 } Entries can also follow a {}: block. This gives structure to the entries and has the added benefit of allowing multi-line lambdas.\nvar colors = {}: red: 0xFF0000 green: 0x00FF00 blue: 0x0000FF dump func (c): print c.red print c.green print c.blue -- Nested map. darker {}: red: 0xAA0000 green: 0x00AA00 blue: 0x0000AA Map operations.\nvar map = {} -- Set a key value pair. map[123] = 234 -- Get the size of the map. print map.size() -- Remove an entry by key. map.remove 123 -- Iterating a list. for map each val, key: print \u0026#39;{key} -\u0026gt; {value}\u0026#39; type Map # Method Summary iterator() Iterator\u0026lt;any\u0026gt; Returns a new iterator over the map elements. pairIterator() PairIterator\u0026lt;any, any\u0026gt; Returns a new pair iterator over the map elements. remove(key any) none Removes the element with the given key key. size() int Returns the number of key-value pairs in the map. Objects. # Any value that isn\u0026rsquo;t a primitive is an object. You can declare your own object types using the type object declaration. Object types are similar to structs and classes in other languages. You can declare members and methods. Unlike classes, there is no concept of inheritance at the language level.\ntype Node object: value next var node = Node{ value: 123, next: none } print node.value -- \u0026#39;123\u0026#39; New instances of an object template are created using the type name and braces that surround the initial member values.\nMethods. # The first parameter of a method must be self. Otherwise, it declares a static function that can only be invoked from the type\u0026rsquo;s namespace.\ntype Node object: value next -- A static function. func create(): return Node{ value: 123, next: none } -- A method. func dump(self): print self.value var n = Node.create() n.dump() Although self is required in a method\u0026rsquo;s signature, it\u0026rsquo;s optional when referencing the type\u0026rsquo;s members.\ntype Node object: value func double(self): return value * 2 Enums. # 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.\ntype Fruit enum: apple orange banana kiwi var fruit = Fruit.kiwi print fruit -- \u0026#39;Fruit.kiwi\u0026#39; print int(fruit) -- \u0026#39;3\u0026#39; When the type of the value is known to be an enum, it can be assigned using a symbol literal.\nvar fruit = Fruit.kiwi fruit = #orange print(fruit == Fruit.orange) -- \u0026#39;true\u0026#39; Symbols. # Symbol literals begin with #, followed by an identifier. They have their own global unique id.\nvar currency = #usd print(currency == #usd) -- \u0026#39;true\u0026#39; print int(currency) -- \u0026#39;123\u0026#39; or some arbitrary id. "},{"id":2,"href":"/cyber/docs/toc/control-flow/","title":"Control Flow","section":"Table of Contents","content":" Control Flow. # Cyber provides the common constructs to branch and enter loops.\nBranching. # 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.\nvar a = 10 if a == 10: print \u0026#39;a is 10\u0026#39; else a == 20: print \u0026#39;a is 20\u0026#39; else: print \u0026#39;neither 10 nor 20\u0026#39; An if expression also needs the then keyword. Conditional else clauses are not allowed in an if expression.:\nvar a = 10 var str = if a == 10 then \u0026#39;red\u0026#39; else \u0026#39;blue\u0026#39; Use and and or logical operators to combine conditions:\nvar a = 10 if a \u0026gt; 5 and a \u0026lt; 15: print \u0026#39;a is between 5 and 15\u0026#39; if a == 20 or a == 10: print \u0026#39;a is 10 or 20\u0026#39; Iterations. # Infinite and conditional loops start with the while keyword. An infinite loop continues to run the code in the block until a break or return is reached. When the while clause contains a condition, the loop continues to run until the condition is evaluated to false.\n-- Infinite loop. while: pass var running = true while running: -- Keep looping until `running` is false. pass You can use the optional while loop to continue the loop until the expression evaluates to the none value. The unwrapped optional value is copied to the variable declared after some.\nvar iter = dir.walk() while iter.next() some entry: print entry.name for loops can iterate over a range that starts at a int (inclusive) to a target int (exclusive). When the range operator .. is replaced with ..=, the target int is inclusive. The range can be given a custom step.\nfor 0..100 each i: print i -- 0, 1, 2, ... , 99 for 0..100, 10 each i: print i -- 0, 10, 20, ... , 90 for 100..0, 1 each i: print i -- 100, 99, 98, ... , 1 for 100..=0, 1 each i: print i -- 100, 99, 98, ... , 0 The for clause can iterate over an Iterable object. An Iterable type contains an iterator() method that returns an Iterator object. An Iterator type contains a next() method that returns the next value or none when finished. You can iterate lists since they are Iterable.\nvar list = [1, 2, 3, 4, 5] -- Iterate on values. for list each n: print n When the as clause contains two variables, the for loop will iterate a PairIterable object. A PairIterable type contains a pairIterator() method that returns a PairIterator object. A PairIterator type contains a nextPair() method that returns two values or none on the first value when finished. The list object is also a PairIterable and the key is the index of the value in the list.\n-- Iterate on values and indexes. for list each i, n: print \u0026#39;{i} -\u0026gt; {n}\u0026#39; -- Iterate on just indexes. for list each i, _: print i The for clause can also iterate over maps with the same idea.\nvar map = { a: 123, b: 234 } -- Iterate on values. for map each v: print v -- Iterate on values and keys. for map each k, v: print \u0026#39;{k} -\u0026gt; {v}\u0026#39; -- Iterate on just keys. for map each k, _: print k You can exit a loop using break.\nfor 0..10 each i: if i == 4: break print i -- This loop stops printing once `i` reaches 4. You can skip the rest of the loop and go to the next iteration using continue.\nfor 0..10 each i: if i == 4: continue print i -- This loop prints 0 through 9 but skips 4. Matching. # Matching is similar to a switch statement. The expression to the right of match is evaluated and execution jumps to the declared case with the matching value. Multiple cases can be grouped together using a comma separator. An optional else fallback case is executed when no other cases were matched.\nIncomplete: Not all types can be used in the case clause such as ranges.\nvar val = 1000 match val: 0..100: print \u0026#39;at or between 0 and 99\u0026#39; 100: print \u0026#39;val is 100\u0026#39; 200: print \u0026#39;val is 200\u0026#39; 300, 400: print \u0026#39;combined case\u0026#39; else: print \u0026#39;val is {val}\u0026#39; 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.\nDeferred Execution. # Planned Feature\n"},{"id":3,"href":"/cyber/docs/toc/functions/","title":"Functions","section":"Table of Contents","content":" Functions. # In Cyber, there are first-class functions (or function values) and static functions.\nStatic Functions. # Static functions are not initially values themselves. They allow function calls to be optimal since they don\u0026rsquo;t need to resolve a dynamic value.\nStatic functions are declared with the func keyword and must have a name.\nimport m \u0026#39;math\u0026#39; func dist(x0, y0, x1, y1): var dx = x0-x1 var dy = y0-y1 return m.sqrt(dx^2 + dy^2) Calling static functions is straightforward. You can also reassign or pass them around as function values.\nprint dist(0, 0, 10, 20) -- Assigning to a local variable. var bar = dist -- Passing `dist` as an argument. func squareDist(dist, size): return dist(0, 0, size, size) print squareDist(dist, 30) The function declaration can also be initialized to an expression that evaluates to a function. However, the expression can not contain any local variable references since it\u0026rsquo;s a static declaration. The function signatures also have to match.\nfunc myAdd(a, b): return a + b func add(a, b) = myAdd -- Valid declaration. var myInc = func(a): return a + 1 func inc(a) = myInc -- CompileError, referencing local variable `myInc`. func foo(a, b, c) = myAdd -- panic, signature mismatch. Functions can return multiple values. This feature has not been confirmed nor implemented.\nimport {cos, sin} \u0026#39;math\u0026#39; func compute(rad): return cos(rad), sin(rad) var x, y = compute(pi) Function Overloading. # Static functions can be overloaded by the number of parameters in its signature. Typed functions are further overloaded by its type signature.\nfunc foo(): return 2 + 2 func foo(n): return 10 + n func foo(n, m): return n * m print foo() -- \u0026#34;4\u0026#34; print foo(2) -- \u0026#34;12\u0026#34; print foo(20, 5) -- \u0026#34;100\u0026#34; Lambdas. # Lambdas or function values can be assigned to variables or passed as arguments into other constructs.\nWhen a lambda only returns an expression, it can be declared with a simplified syntax.\n-- Passing simple lambda as an argument. foo(word =\u0026gt; toUpper(word)) -- A simple lambda with multiple arguments. foo((word, prefix) =\u0026gt; prefix + toUpper(word)) -- Assigning a simple lambda. canvas.onUpdate = delta_ms =\u0026gt; print delta_ms Lambdas that need a block of statements can be declared with the func keyword without a name.\n-- Assigning lambda block to a variable. var add = func (a, b): return a + b -- Passing a lambda block as an argument. canvas.onUpdate(): ..func (delta_ms): print delta_ms Passing a lambda block as a call argument is only possible in a call block. See Function Calls.\nClosures. # In Cyber, lambdas can capture local variables from parent blocks. This example shows the lambda f capturing a from the main scope.\nvar a = 1 var f = func(): return a + 2 print f() -- \u0026#34;3\u0026#34; The following lambda expression captures a from the function add.\nfunc add(): var a = 123 return b =\u0026gt; a + b var addTo = add() print addTo(10) -- \u0026#34;133\u0026#34; However, static functions can not capture local variables.\nvar a = 1 func foo(): print a -- Compile Error: Can\u0026#39;t reference local from static function. Named Parameters. # Planned Feature\nOptional Parameters. # Planned Feature\nVariadic Parameters. # Planned Feature\nFunction Calls. # The straightforward way to call a function is to use parentheses.\nvar d = dist(100, 100, 200, 200) You can call functions with named parameters.\nvar d = dist(x0: 10, x1: 20, y0: 30, y1: 40) The shorthand method for calling functions omits parentheses and commas. This only works for functions that accept parameters:\nIncomplete: Only the most trivial cases work with the shorthand method. The case with operators being separated by spaces might not end up being implemented.\nvar d = dist 100 100 200 200 -- Calls the function `dist`. func random(): -- Function with no parameters. return 4 var r = random -- Returns the function itself as a value. Does not call the function `random`. r = random() -- Calls the function `random`. The top level arguments for the shorthand convention must be separated by whitespace. A string can contain whitespace since it\u0026rsquo;s surrounded by delimiters.\nvar a = myFunc \u0026#39;cyber script\u0026#39; The following has a binary expression with spaces inbetween which is not allowed. Removing that whitespace fixes the call expression.\nvar 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.\n-- This calls the function `myFunc` with 2 arguments. var a = myFunc \u0026#39;hello\u0026#39; (1 + 2 * 3) -- Nested function call using the shorthand convention. a = myFunc \u0026#39;hello\u0026#39; (otherFunc 1+2 \u0026#39;world\u0026#39;) The call expression block continues to add arguments from the block\u0026rsquo;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.\nPlanned Feature\nfoo(123): ..func (): return 123 param3: 123 234 bar() \u0026#39;hello\u0026#39; 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'.\n"},{"id":4,"href":"/cyber/docs/toc/modules/","title":"Modules","section":"Table of Contents","content":" Modules. # Modules have their own namespace and contain accessible static symbols. By default, importing another Cyber script returns a module with its declared symbols.\nImporting. # 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\u0026rsquo;s directory. An embedder can integrate their own module loader.\nimport t \u0026#39;test\u0026#39; t.eq(123, 123) -- Imports are static declarations so they can be anywhere in the script. import m \u0026#39;math\u0026#39; print m.cos(0) -- Loading another Cyber script. import foo \u0026#39;bar.cy\u0026#39; print foo.myFunc() print foo.myVar A Cyber script that is imported doesn\u0026rsquo;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.\n-- main.cy import a \u0026#39;foo.cy\u0026#39; print a.foo -- foo.cy import \u0026#39;bar.cy\u0026#39; var foo: 123 print foo -- Statement is ignored. -- bar.cy 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.\n-- main.cy import foo \u0026#39;foo.cy\u0026#39; func printB(): foo.printC() foo.printA() -- foo.cy import main \u0026#39;main.cy\u0026#39; func printA(): main.printB() func printC(): print \u0026#39;done\u0026#39; Static variable declarations from imports can have circular references. Read more about this in Static Variables.\nModules can also be destructured using the following syntax:\nimport { cos, pi } \u0026#39;math\u0026#39; print cos(pi) Exporting. # All static declarations are exported when the script\u0026rsquo;s module is loaded.\nfunc foo(): -- Exported static function. print 123 var bar: 234 -- Exported static variable. type Thing object: -- Exported type. a float The annotation @hide provides a hint to editors that the static symbol should not appear in the auto-complete. Despite this, the symbol is still reachable.\nPlanned Feature\nBuiltin Modules. # Cyber currently contains the builtin modules:\ncore: Cyber related functions and commonly used utilities. math: Math constants and functions. os: System level functions. test: Utilities for testing. Incomplete: The docs for builtins are not completely up-to-date. They will be auto generated in the future.\nCore Module. # The core module contains functions related to Cyber and common utilities. It is automatically imported into each script\u0026rsquo;s namespace.\nSample usage:\nprint \u0026#39;hello\u0026#39; var contents = readFile \u0026#39;foo.txt\u0026#39; print contents Function Summary arrayFill(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. boolean(val any) boolean Converts a value to either true or false. cacheUrl(url string) string Returns the path of a locally cached file of url. If no such file exists locally, it\u0026rsquo;s fetched from url. copy(val any) any Copies a primitive value or creates a shallow copy of an object value. error(e (enum | symbol)) error Create an error from an enum or symbol. execCmd(args []string) Map{ out, err, exited } Runs a shell command and returns the stdout/stderr. exit(status int) noreturn Exits the program with a status code. evalJS(val string) none Evals JS from the host environment. This is only available in a web WASM build of Cyber. fetchUrl(url string) rawstring Fetches the contents at url using the HTTP GET request method. getInput() rawstring Reads stdin until a new line is reached. This is intended to read user input from the command line. For bulk reads from stdin, use os.stdin. int(val any) int Converts a value to an 32-bit integer. isAlpha(val int) boolean Returns whether a rune is an alphabetic letter. isDigit(val int) boolean Returns whether a rune is a digit. must(val any) any | noreturn If val is an error, panic(val) is invoked. Otherwise, val is returned. float(val any) float Casts or converts the value to a float. Panics if type conversion fails. panic(e symbol) noreturn Stop execution in the current fiber and starts unwinding the call stack. See Unexpected Errors. parseCyber(src any) 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. parseCyon(src any) any Parses a CYON string into a value. performGC() map Runs the garbage collector once to detect reference cycles and abandoned objects. Returns the statistics of the run in a map value. pointer(val any) pointer Converts a int to a pointer value, or casts to a pointer. This is usually used with FFI. print(s string) none Prints a value as a string to stdout. The new line is also printed. prints(s string) none Prints a value as a string to stdout. rawstring(str string) rawstring Converts a string to a rawstring. readAll() rawstring Reads stdin to the EOF as a rawstring. readFile(path string) rawstring Reads the file contents into a rawstring value. runestr(val int) string Converts a rune to a string. string(val any) string Converts a value to a string. toCyon(val any) string Encodes a value to CYON string. typeof(any) metatype Returns the value\u0026rsquo;s type as a metatype object. typesym(any) symbol Returns the value\u0026rsquo;s type as one of the predefined symbols: #float, #int, #boolean, #object, #list, #map, #string, #rawstring, #function, #fiber, #pointer, #symbol, #metatype, #none, #error writeFile(path string, contents string) none Writes a string value to a file. Math Module. # The math module contains commonly used math constants and functions.\nSample usage:\nimport m \u0026#39;math\u0026#39; var r = 10 print(m.pi * r^2) Variable Type Summary e float Euler\u0026rsquo;s number and the base of natural logarithms; approximately 2.718. inf float Infinity. log10e float Base-10 logarithm of E; approximately 0.434. log2e float Base-2 logarithm of E; approximately 1.443. ln10 float Natural logarithm of 10; approximately 2.303. ln2 float Natural logarithm of 2; approximately 0.693. nan float Not a number. Note that nan == nan, however, if a nan came from an arithmetic operation, the comparison is undefined (it may be true or false, so it is not reliable). neginf float Negative infinity. pi float Ratio of a circle\u0026rsquo;s circumference to its diameter; approximately 3.14159. sqrt1_2 float Square root of ½; approximately 0.707. sqrt2 float Square root of 2; approximately 1.414. Function Summary abs(float) float Returns the absolute value of x. acos(float) float Returns the arccosine of x. acosh(float) float Returns the hyperbolic arccosine of x. asin(float) float Returns the arcsine of x. asinh(float) float Returns the hyperbolic arcsine of a number. atan(float) float Returns the arctangent of x. atan2(float, float) float Returns the arctangent of the quotient of its arguments. atanh(float) float Returns the hyperbolic arctangent of x. cbrt(float) float Returns the cube root of x. ceil(float) float Returns the smallest integer greater than or equal to x. clz32(float) float Returns the number of leading zero bits of the 32-bit integer x. cos(float) float Returns the cosine of x. cosh(float) float Returns the hyperbolic cosine of x. exp(float) float Returns e^x, where x is the argument, and e is Euler\u0026rsquo;s number (2.718…, the base of the natural logarithm). expm1(float) float Returns subtracting 1 from exp(x). floor(float) float Returns the largest integer less than or equal to x. hypot(float, float) float Returns the square root of the sum of squares of its arguments. isNaN(float) bool Returns whether x is not a number. ln(float) float Returns the natural logarithm (㏒e; also, ㏑) of x. log(float, float) float Returns the logarithm of y with base x. log10(float) float Returns the base-10 logarithm of x. log1p(float) float Returns the natural logarithm (㏒e; also ㏑) of 1 + x for the number x. log2(float) float Returns the base-2 logarithm of x. max(float, float) float Returns the largest of two numbers. min(float, float) float Returns the smallest of two numbers. mul32(float, float) float Returns the result of the 32-bit integer multiplication of x and y. Integer overflow is allowed. pow(float, float) float Returns base x to the exponent power y (that is, x^y). random() float Returns a pseudo-random number between 0 and 1. round(float) float Returns the value of the number x rounded to the nearest integer. sign(float) float Returns the sign of the x, indicating whether x is positive, negative, or zero. sin(float) float Returns the sine of x. sinh(float) float Returns the hyperbolic sine of x. sqrt(float) float Returns the positive square root of x. tan(float) float Returns the tangent of x. tanh(float) float Returns the hyperbolic tangent of x. trunc(float) float Returns the integer portion of x, removing any fractional digits. Os Module. # Cyber\u0026rsquo;s os module contains system level functions. It\u0026rsquo;s still undecided as to how much should be included here so it\u0026rsquo;s incomplete. You can still access os and libc functions yourself using Cyber\u0026rsquo;s FFI or embedding API.\nSample usage:\nimport os \u0026#39;os\u0026#39; var map = os.getEnvAll() for map each k, v: print \u0026#39;{k} -\u0026gt; {v}\u0026#39; Variable Type Summary cpu string The current cpu arch\u0026rsquo;s tag name. endian #little, #big The current arch\u0026rsquo;s endianness. stderr File Standard error file descriptor. stdin File Standard input file descriptor. stdout File Standard output file descriptor. system string The current operating system\u0026rsquo;s tag name. vecBitSize int Default SIMD vector bit size. Function Summary access(path any, mode (#read | #write | #readWrite)) true | error Attempts to access a file at the given path with the #read, #write, or #readWrite mode. Return true or an error. args() List\u0026lt;string | rawstring\u0026gt; Returns the command line arguments as a list. Each argument is validated and returned as a UTF-8 string or rawstring if the validation failed. bindLib(path any, decls [](CFunc|CStruct)) Object | Map Calls bindLib(path, decls, {}). bindLib(path any, decls [](CFunc|CStruct), config: BindLibConfig) Object | Map Creates an FFI binding to a dynamic library and it\u0026rsquo;s symbols. By default, an anonymous object is returned with the C-functions binded as the object\u0026rsquo;s methods. If config contains genMap: true, a Map is returned instead with C-functions binded as function values. copyFile(srcPath any, dstPath any) none | error Copies a file to a destination path. createDir(path any) true | error Creates the directory at path. Returns true if successful. createFile(path any, truncate boolean) File | error Creates and opens the file at path. If truncate is true, an existing file will be truncated. cstr(any) pointer Returns a null terminated C string. cwd() string Returns the current working directory. dirName(path any) string | none Returns the given path with its last component removed. exePath() string Returns the current executable\u0026rsquo;s path. free(ptr pointer) none Frees the memory located at ptr. fromCstr(pointer) rawstring Returns a rawstring from a null terminated C string. getEnv(key any) string | none Returns an environment value by key. getEnvAll() Map Returns all environment entries as a Map. malloc(size int) pointer Allocates size bytes of memory and returns a pointer. milliTime() float Return the calendar timestamp, in milliseconds, relative to UTC 1970-01-01. openDir(path any) Dir | error Invokes openDir(path, false). openDir(path any, iterable boolean) Dir | error Opens a directory at the given path. iterable indicates that the directory\u0026rsquo;s entries can be iterated. openFile(path any, mode (#read | #write | #readWrite)) File | error Opens a file at the given path with the #read, #write, or #readWrite mode. parseArgs(options list[ArgOption]) map Given expected ArgOptions, returns a map of the options and a rest entry which contains the non-option arguments. realPath(path any) string | error Returns the absolute path of the given path. removeDir(path any) true | error Removes an empty directory at path. Returns true if successful. removeFile(path any) true | error Removes the file at path. Returns true if successful. setEnv(key any, value any) none Sets an environment value by key. sleep(ms float) none Pauses the current thread for given milliseconds. unsetEnv(key any) none Removes an environment value by key. type File # Method Summary close() none Closes the file handle. File ops invoked afterwards will return error.Closed. read(n float) rawstring Reads at most n bytes as a rawstring. n must be at least 1. A result with length 0 indicates the end of file was reached. readToEnd() rawstring Reads to the end of the file and returns the content as a rawstring. seek(pos float) none Seeks the read/write position to pos bytes from the start. Negative pos is invalid. seekFromCur(pos float) none Seeks the read/write position by pos bytes from the current position. seekFromEnd(pos float) none Seeks the read/write position by pos bytes from the end. Positive pos is invalid. stat() Map Returns info about the file as a Map. streamLines() Iterable\u0026lt;rawstring\u0026gt; Equivalent to streamLines(4096). streamLines(bufSize float) Iterable\u0026lt;rawstring\u0026gt; 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. write(data (string | rawstring)) float Writes a string or rawstring at the current file position. The number of bytes written is returned. type Dir # Method Summary iterator() Iterator\u0026lt;DirEntry\u0026gt; | error Returns a new iterator over the directory entries. If this directory was not opened with the iterable flag, error.NotAllowed is returned instead. stat() Map Returns info about the file as a Map. walk() Iterator\u0026lt;DirWalkEntry\u0026gt; | error Returns a new iterator over the directory recursive entries. If this directory was not opened with the iterable flag, error.NotAllowed is returned instead. map DirEntry # Entry Summary 'name' -\u0026gt; rawstring The name of the file or directory. 'type' -\u0026gt; #file | #dir | #unknown The type of the entry. map DirWalkEntry # Entry Summary 'name' -\u0026gt; rawstring The name of the file or directory. 'path' -\u0026gt; rawstring The path of the file or directory relative to the walker\u0026rsquo;s root directory. 'type' -\u0026gt; #file | #dir | #unknown The type of the entry. map ArgOption # Entry Summary 'name' -\u0026gt; string The name of the option to match excluding the hyphen prefix. eg. -path 'type' -\u0026gt; metatype(string | float | boolean) Parse as given value type. 'default' -\u0026gt; any Optional: Default value if option is missing. none is used if this is not provided. Test Module. # The test module contains utilities for testing.\nSample usage:\nimport t \u0026#39;test\u0026#39; var a = 123 + 321 t.eq(a, 444) Function Summary eq(a any, b any) true | error Returns whether two values are equal. Returns error.AssertError if types do not match up. eqList(a any, b any) true | error Returns true if two lists have the same size and the elements are equal as if eq was called on those corresponding elements. eqNear(a any, b any) true | error Returns two numbers are near each other within epsilon 1e-5. "},{"id":5,"href":"/cyber/docs/toc/ffi/","title":"FFI","section":"Table of Contents","content":" FFI. # 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. bindLib is part of the os module and accepts the path to the library as a string and a list of CFunc or CStruct declarations.\nimport os \u0026#39;os\u0026#39; var lib = os.bindLib(\u0026#39;mylib.so\u0026#39;, [ os.CFunc{ sym: \u0026#39;add\u0026#39;, args: [#int, #int], ret: #int } ]) lib.add(123, 321) 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. \u0026lsquo;/foo/mylib.so\u0026rsquo;) or relative (eg. \u0026lsquo;./mylib.so\u0026rsquo;) 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 embedded Cyber app/runtime.\nWhen using CFunc or CStruct declarations, symbols are used to represent default type mappings from Cyber to C and back:\nIncomplete: 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.\nBinding Cyber C Details #bool bool bool #char float int8_t, signed char #uchar float uint8_t, unsigned char #short float int16_t, short #ushort float uint16_t, unsigned short #int float int32_t, int #uint float uint32_t, unsigned int #long float int64_t, long long #ulong float uint64_t, unsigned long long #usize float size_t, uintptr_t #float float float #double float double #charPtr pointer char* Use os.cstr() and os.fromCstr() to convert between a Cyber string and a null terminated C string. #voidPtr pointer void* sym symbol object \u0026lt;sym\u0026gt; Struct The mapping from a Cyber object type sym and the C-struct can be declared with CStruct. By default bindLib returns an anonymous object with the binded C-functions as methods. This is convenient for using it like an object, but it\u0026rsquo;s less optimal compared to binding as functions. If a config is passed into bindLib as the third argument, genMap: true makes bindLib return a map instead with the binded C-functions as Cyber functions. 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.\nCFunc. # The CFunc object lets you bind to a C-function. The sym field maps to the C-function\u0026rsquo;s symbol name in the dynamic library. The args field declares the type mapping from Cyber to C-function\u0026rsquo;s arguments. Finally, the ret field declares the type mapping from the C-function\u0026rsquo;s return type to a Cyber type.\nimport os \u0026#39;os\u0026#39; var lib = os.bindLib(\u0026#39;mylib.so\u0026#39;, [ os.CFunc{ sym: \u0026#39;add\u0026#39;, args: [#int, #int], ret: #int } ]) lib.add(123, 321) The example above maps to this C declaration in mylib.so:\nint add(int a, int b) { return a + b; } CStruct. # You can also bind object types to C-structs using the CStruct object. The type field accepts an object type symbol and fields indicates the mapping for each field in type to and from a C-struct. After adding a CStruct declaration, you can use the object type symbol in CFunc args and ret and also other CStruct fields.\nimport os \u0026#39;os\u0026#39; type MyObject object: a float b pointer c bool var lib = os.bindLib(\u0026#39;mylib.so\u0026#39;, [ os.CFunc{ sym: \u0026#39;foo\u0026#39;, args: [MyObject], ret: MyObject } os.CStruct{ fields: [#f64, #charPtr, #bool], type: MyObject } ]) var res = lib.foo(MyObject{ a: 123, b: os.cstr(\u0026#39;foo\u0026#39;), c: true }) The example above maps to these C declarations in mylib.so:\ntypedef struct MyObject { double a; char* b; bool c; } MyObject; MyObject foo(MyObject o) { // Do something. } CStruct also generates ptrTo[Type] as a helper function to dereference an opaque ptr to a new Cyber object:\nimport os \u0026#39;os\u0026#39; var lib = os.bindLib(\u0026#39;mylib.so\u0026#39;, [ os.CFunc{ sym: \u0026#39;foo\u0026#39;, args: [MyObject], ret: #voidPtr } os.CStruct{ fields: [#f64, #charPtr, #bool], type: MyObject } ]) var ptr = lib.foo(MyObject{ a: 123, b: os.cstr(\u0026#39;foo\u0026#39;), c: true }) var res = lib.ptrToMyObject(ptr) Pointers # A pointer is used to read or write to an exact memory address. This is typically used for FFI to manually map Cyber types to C, and back. A new pointer can be created with the builtin pointer.\nvar ptr = pointer(0xDEADBEEF) print ptr.value() --\u0026#39;3735928559\u0026#39; type pointer # Method Summary value() int Returns the memory address as an int. The value may be negative since it\u0026rsquo;s bitcasted from an unsigned 48-bit integer but it retains the original pointer bits. "},{"id":6,"href":"/cyber/docs/toc/errors/","title":"Error Handling","section":"Table of Contents","content":" Error Handling. # Cyber provides error values and try/catch mechanisms to handle expected errors. For unexpected errors, panics can be used as a fail-fast mechanism to abort the currently running fiber.\nError value. # The error type is a primitive that contains either an enum value or a symbol value. Errors can wrap symbols for convenience but the underlying ID value won\u0026rsquo;t be consistent. Use your own enums if you want reliable ID values.\n-- Shorthand for creating an error value with a symbol. var err = error.Oops -- Alternatively, use the builtin error function to wrap a symbol. err = error(#Oops) type MyError enum: boom badArgument nameTooLong -- Creates an error that wraps an enum value. err = error(MyError.boom) You can attach an optional payload value to an error.\nPlanned Feature\nSince errors are primitives, they can be compared using the == operator.\nif err == error.Oops: handleOops() -- Alternatively. if err.value() == #Oops: handleOops() -- Comparing errors with enums. if err == error(MyError.boom) handleBoom() -- Alternatively. if err.value() == MyError.boom handleBoom() Throwing errors. # 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.\nfunc fail(): throw error.Oops -- Throws an error with the symbol `#Oops` func fail2(): throw 123 -- Panic, Can only throw errors. throw can also be used as an expression.\nfunc fail(): var a = false or throw error.False Catching errors. # The try catch block catches thrown errors and resumes execution in the catch block.\ntry: funcThatCanFail() catch err: print err -- \u0026#39;error.Failed\u0026#39; The try else expression either returns a non-error result or the default value from the else clause.\nvar res = try funcThatCanFail() else 123 print res -- \u0026#39;123\u0026#39; -- Any errors thrown from sub expressions also return the default value. res = try happyFunc(funcThatCanFail()) else 123 print res -- \u0026#39;123\u0026#39; When try is used by itself, either the result or the caught error value is returned.\nvar res = try funcThatCanFail() if res == error.Failed: print \u0026#39;Result is an error.\u0026#39; -- Any errors thrown from sub expressions are also caught. res = try happyFunc(funcThatCanFail()) Stack trace. # When an uncaught error bubbles up to the top, its stack trace from the throw callsite is dumped to the console. Cyber also provides the builtin errorTrace() and errorReport() to obtain the stack trace info.\ntry: funcThatCanFail() catch err: -- Prints the stack trace summary of the caught error. print errorReport() -- Provides structured info about the stack trace. var info = errorTrace() print info.frames.len() Unexpected errors. # An unexpected error is an error that you don\u0026rsquo;t plan on handling at runtime. In this scenario, you can prefer to fail-fast and panic.\nPanics can not be caught using try catch. Once the builtin 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 can resume on the next fiber which allows you to recover from a panic.\nfunc kaboom(): panic(#danger) kaboom() -- Script ends and prints the stack trace. "},{"id":7,"href":"/cyber/docs/toc/concurrency/","title":"Concurrency","section":"Table of Contents","content":" Concurrency. # Cyber supports fibers as a concurrency mechanism. There are plans to support preemptive concurrency with async/await as well as multithreading.\nFibers. # Fibers in Cyber allow representing execution contexts as first-class values. They contain their own call stack and program counters. Fibers by themselves do not enable parallelism.\nThe coinit creates a new fiber from a function call syntax. Using coyield inside a function pauses the current fiber and execution is returned to the fiber that invoked coresume.\nvar count = 0 var foo = func (): count += 1 coyield count += 1 var fiber = coinit foo() print count -- \u0026#39;0\u0026#39; coresume fiber print count -- \u0026#39;1\u0026#39; coresume fiber print count -- \u0026#39;2\u0026#39; In Cyber, coyield can be used anywhere in a fiber\u0026rsquo;s call stack.\nfunc foo(): print \u0026#39;foo\u0026#39; bar() func bar(): -- Nested coyield in call stack. coyield print \u0026#39;bar\u0026#39; var fiber = coinit foo() coresume fiber coresume also returns the resulting value.\nfunc foo(): return 123 var fiber = coinit foo() print(coresume fiber) -- \u0026#39;123\u0026#39; coyield can return a value back to coresume.\nPlanned Feature\nUse Fiber.status() to get the current state of the fiber.\nfunc foo(): coyield print \u0026#39;done\u0026#39; var fiber = coinit foo() print fiber.status() -- \u0026#39;#paused\u0026#39; coresume fiber print fiber.status() -- \u0026#39;#paused\u0026#39; coresume fiber print fiber.status() -- \u0026#39;#done\u0026#39; 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.\nGas mileage. # Planned Feature\nAsync. # Planned Feature\nMulti-thread. # Planned Feature\n"},{"id":8,"href":"/cyber/docs/toc/type-system/","title":"Type System","section":"Table of Contents","content":" Type System. # Cyber supports gradual typing which allows the use of both dynamically and statically typed code.\nIncomplete: Types in general is in development. One of the goals of Cyber is to let dynamic code mix with typed code. At the moment, there are places where it works and other places where it won\u0026rsquo;t. Keep that in mind when using types.\nDynamic typing can reduce the amount of friction when writing code, but it can also result in more runtime errors. Gradual typing allows you to add static typing incrementally which provides compile-time guarantees and prevents runtime errors. Static typing also makes it easier to maintain and refactor your code.\nDynamic typing. # A variable with the any type can hold any value. It can only be copied to destinations that also accept the any type. An any value can be used as the callee for a function call or the receiver for a method call. It can be used with any operators.\nCompile-time dynamic typing. # Cyber introduces the concept of compile-time dynamic typing. This allows a local variable to gain additional compile-time features while using it as a dynamic value. It can prevent inevitable runtime errors and avoid unnecessary type casts.\nLocal variables declared without a type specifier start off with the type of their initializer. In the following, a is implicity declared as a float at compile-time because numeric literals default to the float type.\nvar a = 123 The type can change at compile-time from another assignment. If a is then assigned to a string literal, a from that point on becomes the string type at compile-time.\nvar a = 123 foo(a) -- Valid call expression. a = \u0026#39;hello\u0026#39; foo(a) -- CompileError. Expected `float` argument, got `string`. func foo(n float): pass The type of a can also change in branches. However, after the branch block, a will have a merged type determined by the types assigned to a from the two branched code paths. Currently, the any type is used if the types from the two branches differ. At the end of the following if block, a assumes the any type after merging the float and string types.\nvar a = 123 if a \u0026gt; 20: a = \u0026#39;hello\u0026#39; foo(a) -- Valid call expression. `foo` can be called without type casting. foo(a) -- CompileError. Expected `string` argument, got `any`. func foo(s string): pass Default types. # Static variables without a type specifier will always default to the any type. In the following, a is compiled with the any type despite being initialized to a numeric literal.\nvar a: 123 a = \u0026#39;hello\u0026#39; Function parameters without a type specifier will default to the any type. The return type also defaults to any. In the following, both a and b have the any type despite being only used for arithmetic.\nfunc add(a, b): return a + b print add(3, 4) Static typing. # In Cyber, types can be optionally declared with variables, parameters, and return values. The following builtin types are available in every namespace: bool, float, int, string, List, Map, error, fiber, any.\nA type object declaration creates a new object type.\ntype Student object: -- Creates a new type named `Student` name string age int gpa float When a type specifier follows a variable name, it declares the variable with the type. Any operation afterwards that violates the type constraint will result in a compile error.\nIncomplete: Only function parameter and object member type specifiers have meaning to the VM at the moment. Variable type specifiers have no meaning and will be discarded.\na float = 123 a = \u0026#39;hello\u0026#39; -- CompileError. Type mismatch. Parameter and return type specifiers in a function signature follows the same syntax.\nfunc mul(a float, b float) float: return a * b print mul(3, 4) print mul(3, \u0026#39;4\u0026#39;) -- CompileError. Function signature mismatch. Type specifiers must be resolved at compile-time.\ntype Foo object: a float b string c Bar -- CompileError. Bar is not declared. Circular type references are allowed.\ntype Node object: val any next Node -- Valid type specifier. Union types. # Planned Feature\nInterfaces. # Planned Feature\nType aliases. # A type alias is declared from a single line type statement. This creates a new type symbol for an existing data type.\nimport util \u0026#39;./util.cy\u0026#39; type Vec3 util.Vec3 var v = Vec3{ x: 3, y: 4, z: 5 } Type casting. # 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. If the cast fails at runtime, a panic is returned.\nprint(\u0026#39;123\u0026#39; as float) -- CompileError. Can not cast `string` to `float`. erased any = 123 add(1, erased as float) -- Success. print(erased as string) -- Panic. Can not cast `float` to `string`. func add(a float, b float): return a + b Runtime type checking. # Since Cyber allows invoking any function values, the callee\u0026rsquo;s function signature is not always known at compile-time. To ensure type safety in this situation, type checking is done at runtime and with no additional overhead compared to calling an untyped function.\nop any = add print op(1, 2) -- \u0026#39;3\u0026#39; print op(1, \u0026#39;2\u0026#39;) -- Panic. Function signature mismatch. func add(a float, b float) float: return a + b "},{"id":9,"href":"/cyber/docs/toc/metaprogramming/","title":"Metaprogramming","section":"Table of Contents","content":" Metaprogramming. # Operator overloading. # All operators are implemented as object methods.\nIncomplete: Not all operators have transitioned to the method paradigm.\nNormally this would impact performance, but Cyber\u0026rsquo;s compiler generates specialized bytecode ops for builtin types like int and float. The VM performs inline caching at runtime to eliminate the overhead of evaluating operators on dynamic operands.\nTo overload an operator for a object type, declare $prefix, $infix, $postfix methods:\nIncomplete: Although operator overloading is supported in the VM and builtin types use it, it is not currently enabled for user types.\ntype Vec2 object: x float y float func $infix+(self, o): return Vec2{ x: x + o.x, y: y + o.y, } func $prefix-(self): return Vec2{ x: -x, y: -y } var a = Vec2{ x: 1, y: 2} var b = a + Vec2{ x: 3, y: 4 } var c = -a Some special operators have their own name:\ntype MyCollection object: arr List func $index(self, idx): return arr[idx * 2] func $setIndex(self, idx, val): arr[idx * 2] = val var a = MyCollection{ arr: [1, 2, 3, 4] } print a[1] -- Prints `3` A list of all supported operators:\n$prefix~(_) $prefix-(_) $infix\u0026gt;(_, _) $infix\u0026gt;=(_, _) $infix\u0026lt;(_, _) $infix\u0026lt;=(_, _) $infix+(_, _) $infix-(_, _) $infix*(_, _) $infix/(_, _) $infix%(_, _) $infix^(_, _) $infix\u0026amp;(_, _) $infix|(_, _) $infix||(_, _) $infix\u0026lt;\u0026lt;(_, _) $infix\u0026gt;\u0026gt;(_, _) $index(_, _) $setIndex(_, _, _) $slice(_, _, _) Custom operators. # Planned Feature\nMagic functions. # Call module. # Declare a $call function to allow invoking a module as a function.\nIncomplete: Although $call function is supported in the VM and builtin modules use it, it is not currently enabled for user modules.\n-- Object types are also modules. type Vec2 object: x float y float func $call(x float, y float) Vec2: return Vec2{ x: x, y: y } var v = Vec2(1, 2) Getter/Setter. # Planned Feature\nMissing method. # Declare a $missing method as a fallback when a method was not found in an instance.\nPlanned Feature\ntype A object: func $missing(self, args...): return args.len var a = A{}; print a.foo() -- Output: \u0026#39;0\u0026#39; print a.bar(1, 2) -- Output: \u0026#39;2\u0026#39; Reflection. # A metatype object references an internal type. Use the typeof builtin to get the metatype of a value.\nvar val = 123 print typeof(val) -- \u0026#39;type: float\u0026#39; -- Referencing a type as a value also returns its `metatype`. print boolean -- \u0026#39;type: boolean\u0026#39; type metatype # func id(self) int -- Returns the type ID as an `int`. Annotations. # Planned Feature\nRuntime eval. # Planned Feature\nGenerics. # Planned Feature\nCompile-time. # Planned Feature\n"},{"id":10,"href":"/cyber/docs/toc/embedding/","title":"Embedding","section":"Table of Contents","content":" Embedding. # Planned Feature\n"},{"id":11,"href":"/cyber/docs/toc/memory/","title":"Memory","section":"Table of Contents","content":" Memory. # Cyber provides memory safety by default.\nARC. # 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\u0026rsquo;s very own Cycle Detection.\nReference Counting. # In Cyber, there are primitive and object values. Primitives don\u0026rsquo;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).\nObject are managed by ARC and 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\u0026rsquo;s retained and the reference count increments by 1. When an object value is removed from it\u0026rsquo;s parent or is no longer reachable in the current stack frame, it is released and the reference count decrements by 1.\nOnce the reference count reaches 0 and the object (eg. List or Map) also contains child references, each child reference is released thereby decrementing their reference counts by 1. Afterwards, the object is freed from memory.\nOptimizations. # 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.\nClosures. # 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.\nFibers. # Fibers are freed by ARC just like any other object. Once there are no references to the fiber, it begins to release it\u0026rsquo;s child references by unwinding it\u0026rsquo;s call stack.\nHeap. # 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.\nWeak References. # Planned Feature\nCycle Detection. # 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.\nIncomplete Feature: Only the main fiber stack is cleaned up at the moment.\nTo invoke the GC, call the builtin function: performGC.\nfunc foo(): -- Create a reference cycle. var a = [] var b = [] a.append(b) b.append(a) var res = performGC() -- Cycle still alive in the current stack so no cleanup is done. print res[\u0026#39;numCycFreed\u0026#39;] -- Output: 0 print res[\u0026#39;numObjFreed\u0026#39;] -- Output: 0 foo() var res = performGC() -- `a` and `b` are no longer reachable, so the GC does work. print res[\u0026#39;numCycFreed\u0026#39;] -- Output: 2 print res[\u0026#39;numObjFreed\u0026#39;] -- Output: 2 "},{"id":12,"href":"/cyber/docs/toc/aot-jit/","title":"AOT/JIT","section":"Table of Contents","content":" AOT and JIT # Planned Feature\n"}] \ No newline at end of file diff --git a/en.search.min.436a98919e3cc9dc331a63b9d377785de95eec900cfb65b7ed9a0acf873a4d8a.js b/en.search.min.db402b8c46fe1829b7c32e1613e5e896d742a3010e5975362d629f119703c98d.js similarity index 90% rename from en.search.min.436a98919e3cc9dc331a63b9d377785de95eec900cfb65b7ed9a0acf873a4d8a.js rename to en.search.min.db402b8c46fe1829b7c32e1613e5e896d742a3010e5975362d629f119703c98d.js index 4f9246d9f..33d7c162e 100644 --- a/en.search.min.436a98919e3cc9dc331a63b9d377785de95eec900cfb65b7ed9a0acf873a4d8a.js +++ b/en.search.min.db402b8c46fe1829b7c32e1613e5e896d742a3010e5975362d629f119703c98d.js @@ -1 +1 @@ -"use strict";(function(){const o="/cyber/en.search-data.min.fcf6482b69d03bc62a33db6550710b275db6444d7746b904b7478ba4f6d1db4f.json",i=Object.assign({cache:!0},{doc:{id:"id",field:["title","content"],store:["title","href","section"]}}),e=document.querySelector("#book-search-input"),t=document.querySelector("#book-search-results");if(!e)return;e.addEventListener("focus",n),e.addEventListener("keyup",s),document.addEventListener("keypress",a);function a(t){if(t.target.value!==void 0)return;if(e===document.activeElement)return;const n=String.fromCharCode(t.charCode);if(!r(n))return;e.focus(),t.preventDefault()}function r(t){const n=e.getAttribute("data-hotkeys")||"";return n.indexOf(t)>=0}function n(){e.removeEventListener("focus",n),e.required=!0,fetch(o).then(e=>e.json()).then(e=>{window.bookSearchIndex=FlexSearch.create("balance",i),window.bookSearchIndex.add(e)}).then(()=>e.required=!1).then(s)}function s(){for(;t.firstChild;)t.removeChild(t.firstChild);if(!e.value)return;const n=window.bookSearchIndex.search(e.value,10);n.forEach(function(e){const n=c("
  • "),s=n.querySelector("a"),o=n.querySelector("small");s.href=e.href,s.textContent=e.title,o.textContent=e.section,t.appendChild(n)})}function c(e){const t=document.createElement("div");return t.innerHTML=e,t.firstChild}})() \ No newline at end of file +"use strict";(function(){const o="/cyber/en.search-data.min.7c9bee2bed668c0945db3e2bd7104c96864b46b7af194f2f9ed362e8497c3c19.json",i=Object.assign({cache:!0},{doc:{id:"id",field:["title","content"],store:["title","href","section"]}}),e=document.querySelector("#book-search-input"),t=document.querySelector("#book-search-results");if(!e)return;e.addEventListener("focus",n),e.addEventListener("keyup",s),document.addEventListener("keypress",a);function a(t){if(t.target.value!==void 0)return;if(e===document.activeElement)return;const n=String.fromCharCode(t.charCode);if(!r(n))return;e.focus(),t.preventDefault()}function r(t){const n=e.getAttribute("data-hotkeys")||"";return n.indexOf(t)>=0}function n(){e.removeEventListener("focus",n),e.required=!0,fetch(o).then(e=>e.json()).then(e=>{window.bookSearchIndex=FlexSearch.create("balance",i),window.bookSearchIndex.add(e)}).then(()=>e.required=!1).then(s)}function s(){for(;t.firstChild;)t.removeChild(t.firstChild);if(!e.value)return;const n=window.bookSearchIndex.search(e.value,10);n.forEach(function(e){const n=c("
  • "),s=n.querySelector("a"),o=n.querySelector("small");s.href=e.href,s.textContent=e.title,o.textContent=e.section,t.appendChild(n)})}function c(e){const t=document.createElement("div");return t.innerHTML=e,t.firstChild}})() \ No newline at end of file diff --git a/index.html b/index.html index 043187662..82ab96893 100644 --- a/index.html +++ b/index.html @@ -1,7 +1,7 @@ Introduction | Cyber Docs v0.2 - +
    Introduction diff --git a/tags/index.html b/tags/index.html index cb6122494..6e06c3d09 100644 --- a/tags/index.html +++ b/tags/index.html @@ -1,5 +1,5 @@ Tags | Cyber Docs v0.2 - +
    Tags