Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/control_flow/control_flow.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Control Flow

Onyx has a standard set of simple control flow mechanisms: `if`, `while`, `for`, `switch` and `defer`.
Notably absent is `goto`, and this by design.
Notably absent is `goto`, and this is by design.
3 changes: 2 additions & 1 deletion src/control_flow/for_loops.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,12 @@ for value, index: i64 in i32.[2, 3, 5, 7, 11] {

## Custom Iterators Loops

The final type that `for` loops can iterate over is `Iterator(T)`. `Iterator` is a built-in type that represents a generic iterator. An `Iterator` has 4-elements:
The final type that `for` loops can iterate over is `Iterator(T)`. `Iterator` is a built-in type that represents a generic iterator. An `Iterator` has 4 elements:
- `data` - a pointer to the context for the iterator.
- `next` - a function to retrieve the next value out of the iterator.
- `remove` - an optional function to remove the current element.
- `close` - an optional function to cleanup the iterator's context.

The `core.iter` package provides many utilities for working with iterators.

Here is a basic example of creating an iterator from a `range`, then using `iter.map` to double the values. Iterators are lazily evaluated, so none of the actual doubling happens until values are pulled out of the iterator by the `for` loop.
Expand Down
2 changes: 1 addition & 1 deletion src/directives/defined.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# `#defined`
# #defined

When a symbol may or may not be defined due to different compilation flags,
you can use `#defined` to test whether or not it is actually defined.
Expand Down
2 changes: 1 addition & 1 deletion src/directives/file_contents.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ image_data := #file_contents "image/path/here.png";
pixels := convert_image_to_pixels(image_data);
```

This way, there is file I/O to load an image from disk. It is already in the
This way, there is no file I/O to load an image from disk. It is already in the
binary ready to be used.
2 changes: 1 addition & 1 deletion src/directives/if.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# #if

`#if` is a *compile-time* if statement. It looks like a normal if
statement, except its condition must be resolvable at compile time.
statement, except its condition must be resolvable at compile-time.
This is because it controls whether or not the body of the `#if`
statement are included in the compilation.

Expand Down
2 changes: 1 addition & 1 deletion src/directives/tag.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# `#tag`
# #tag

`#tag` is used to attach static metadata to various compile-time objects.
This metadata can then be accessed using the `runtime.info` package.
Expand Down
4 changes: 2 additions & 2 deletions src/misc/format_strings.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ This table provides brief defintions as to what can appear between the curly bra
| `*` | If the variable is a pointer, dereference the pointer and format the result |
| `p` | Pretty formatting |
| `.N` | Sets the decimal precision when formatting a float to be `N` digits |
| `bN` | Sets the base when formatting an interger to be `N` |
| `bN` | Sets the base when formatting an integer to be `N` |
| `x` | Shorthand for `b16` |
| `wN` | Left-pad to `N` characters long (this might not work for everything) |
| `"` | Quote strings in double quotes. Quotes are only added to `str`s |
| `"` | Quote string in double quotes. Quotes are only added to `str`s |
| `'` | Quote string in single quotes. Quotes are only added to `str`s |
| `d` | Disable printing enums as strings and print as numbers instead |

4 changes: 2 additions & 2 deletions src/misc/js_ffi.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# JS Interop

Interfacing with JavaScript from Onyx is easy thanks to the `core.js` package. It was inspired from
[`syscall/js`](https://pkg.go.dev/syscall/js), made by the wonderful people over at on the Go team.
[`syscall/js`](https://pkg.go.dev/syscall/js), made by the wonderful people over at the Go team.

The `core.js` package abstracts away the details of managing references to JS values from Onyx,
so you are able to write code that uses JS values without caring about all the internal details.

For example, here is a simple program that runs on a web browser. It creates a new `button` element,
add a `click` event handler that will call an Onyx function, then adds the button to the page.
adds a `click` event handler that will call an Onyx function, then adds the button to the page.

```onyx
use core.js
Expand Down
2 changes: 1 addition & 1 deletion src/operators/bitwise.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Onyx has the following binary bitwise operators:
| Operator | Use | Works on |
| --- | --- | --- |
| `&` | Bitwise-And | integers |
| `|` | Bitwise-Or | integers |
| `\|` | Bitwise-Or | integers |
| `^` | Bitwise-Xor | integers |
| `<<` | Bit shift left | integers |
| `>>` | Bit shift right (logical) | integers |
Expand Down
2 changes: 1 addition & 1 deletion src/operators/calls.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ main :: () -> void {
## Passing Arguments

Arguments are passed in between the `()`, in a comma-separated fashion.
The type of each argument must agree with the expected paramter type, or at least be of compatible type.
The type of each argument must agree with the expected parameter type, or at least be of compatible type.

```onyx
foo :: (x: i32, y: str) -> void {
Expand Down
4 changes: 2 additions & 2 deletions src/operators/cast.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ main :: () {
In this contrived example, `base_ptr` is casted to a `&SubType` using the the *call* form of the cast operator.
This form is slightly nicer when you are going to immediately to follow the cast operation with a postfix operation.
In this case, `.age`.
If this was written in prefix form, another set of parenthesis would be needed: `(cast(&SubType) base_ptr).age`.
If this was written in prefix form, another set of parentheses would be needed: `(cast(&SubType) base_ptr).age`.


## Auto casting

Sometimes, a cast necessary for the code to type check, but it is cumbersome to type the entire cast operation.
Sometimes, a cast is necessary for the code to type check, but it is cumbersome to type the entire cast operation.
Maybe the type is too long, or maybe the type is not even available because the package is not used.
In these cases, the *auto-cast* operator can be used.

Expand Down
2 changes: 1 addition & 1 deletion src/operators/if-else.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ main :: () {
}
```

While this operator should be scarely used for the sake of readable code, it can be very handy in certain circumstances.
While this operator should be rarely used for the sake of readable code, it can be very handy in certain circumstances.
6 changes: 3 additions & 3 deletions src/operators/methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ main :: () {
```

Sometimes you want to pass the "object" as a pointer to the method if the method is going
to modify the object. As a convience, the method call operator will do this automatically
to modify the object. As a convenience, the method call operator will do this automatically
for you, if it is possible to take the address of the left-hand side. This may feel a little
weird but it is largely intuitive and similar to how many other languages work.
```onyx
Expand Down Expand Up @@ -107,7 +107,7 @@ While Onyx does not natively support virtual tables, there is a pattern
that can achieve this using `use`d members on structures. Here is an
example of the classic "Animals that can speak" inheritance argument.

Create a virtual table structures that will store the function pointers.
Create a virtual table structure that will store the function pointers.
```onyx
Animal_Vtable :: struct {
// 'greet' is a member of the vtable, and takes a pointer
Expand Down Expand Up @@ -149,7 +149,7 @@ Cat :: struct {
}
```

Now you can pass a pointer `Dog` and or a pointer to `Cat` to any procedure expecting
Now you can pass a pointer to `Dog` or a pointer to `Cat` to any procedure expecting
a pointer to an `Animal_Vtable`, thanks to [Sub-Type Polymorphism](../types/structures.md#sub-type-polymorphism).

```onyx
Expand Down
6 changes: 3 additions & 3 deletions src/philosophy/memory.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Memory Management in Onyx

Onyx has *manually managed memory*. Now, you're probably thinking of C, where you
have to be careful that every `malloc` that it has a matching `free`. Onyx's memory
have to be careful that every `malloc` has a matching `free`. Onyx's memory
management has *some* aspect of that, but Onyx has many things that make it much easier
to not make mistakes.

Expand Down Expand Up @@ -44,7 +44,7 @@ weird or complicated, but it actually simplifies programming and memory manageme

One thing to realize is that *most* allocations you make have a well defined
*lifetime*, or time in which they can be accessed. Sometimes that lifetime can
be hard to describe to something like a borrow checker, but they breakdown into
be hard to describe to something like a borrow checker, but they break down into
four categories:

- **Very short term**: Allocations that likely only live to end of a function.
Expand Down Expand Up @@ -92,7 +92,7 @@ The temporary allocator exists for this purpose.
You allocate into the temporary allocator when you have something that should be
valid for this loop, but should not live past the end of the loop.

The HTTP Server package for Onyx uses this strategy, but even more aggressive.
The HTTP Server package for Onyx uses this strategy, but is even more aggressive.
It replaces the main allocator (aka `context.allocator`, which is used by default
throughout the standard library), with a GC allocator. This allocator tracks
every allocation made in it, and can free everything in a single call. Every
Expand Down
4 changes: 2 additions & 2 deletions src/philosophy/onyx.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ I only want Onyx to be great for the projects that *can* use Onyx and WebAssembl
Some projects that Onyx would not be suited for would be:

- Very performance critical desktop applications
- Native libraries, through [Wasmer does have a way to do this](https://docs.wasmer.io/registry)
- Native libraries, though [Wasmer does have a way to do this](https://docs.wasmer.io/registry)
- Embedded environments


To drive the point home, there will likely never be a *rewrite it in Onyx* trend like there
is with Rust. Onyx is not aiming to replace Rust, Go, Zig, C++, or whatever your favorite
language is. Onyx is new language, filling the rather niche purpose of supporting WebAssembly
language is. Onyx is a new language, filling the rather niche purpose of supporting WebAssembly
above all else. **I do not see WebAssembly being a limitation of Onyx, but rather I see Onyx
pushing the boundaries of WebAssembly.**

Expand Down
4 changes: 2 additions & 2 deletions src/philosophy/wasm.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ in the WASI specification.
> **Note**, Onyx fully supports WASIX by compiling with `-r wasi -DWASIX`.

There is work being done to create the WebAssembly Component Model, which is a way for programs written
in a variety of different language to all interoperate with one another, much like how programs from Java,
Kotlin, and Scala can interact because they all run on the JVM. This proposal is nearly completion, but
in a variety of different languages to all interoperate with one another, much like how programs from Java,
Kotlin, and Scala can interact because they all run on the JVM. This proposal is nearing completion, but
Onyx is waiting until there are more languages implementing it to see how all of the details shake out.
It is on the roadmap for Onyx to support it.

Expand Down
8 changes: 4 additions & 4 deletions src/procedures/macros.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Macros

Macros in Onyx are very much like procedures, with a couple notable differences. When a macro is called, it is expanded at the call site, as though its body was copy and pasted there. This means that macros can access variables in the scope of their caller.
Macros in Onyx are very much like procedures, with a couple notable differences. When a macro is called, it is expanded at the call site, as though its body was copy-and-pasted there. This means that macros can access variables in the scope of their caller.
```onyx
print_x :: macro () {
// 'x' is not defined in this scope, but it can be used
Expand All @@ -23,7 +23,7 @@ Because macros are inlined at the call site and break traditional scoping rules,

There are two kinds of macros: *block macros*, and *expression macros*. The distinguishing factor between them is the return type. If a macro returns `void`, it is a block macro. If it returns anything else, it is an expression macro.

Block and expression macros behave different with respect to some of the language features. Expression macros behave exactly like an inlined procedure call with dynamic scoping.
Block and expression macros behave differently with respect to some language features. Expression macros behave exactly like an inlined procedure call with dynamic scoping.
```onyx
add_x_and_y :: macro (x: $T) -> T {
defer println("Deferred print statement.");
Expand Down Expand Up @@ -89,7 +89,7 @@ say_hello :: [] {

#unquote say_hello;
```
Code blocks are not type checked until they are unquoted, so they can contain references to references to variables not declared within them.
Code blocks are not type checked until they are unquoted, so they can contain references to variables not declared within them.

Code blocks have their syntax because they can optionally take parameters between their `[]`. When unquoting a code block with parameters,
you must pass an *equal or greater* number of arguments in parentheses after the variable name.
Expand Down Expand Up @@ -133,7 +133,7 @@ triple_macro([] {
A single statement/expression in a code block can be expressed as: `[](expr)`
```onyx
[](println("Hello"))
// Is almost the same the as
// is almost the same as
[] { println("Hello"); }
```

Expand Down
2 changes: 1 addition & 1 deletion src/procedures/overloaded.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ length :: (x: str) => x.count
```


Overloaded procedures provide the backbone for type-generic "traits" in Onyx. Instead of making a type/object oriented system (i.e. Rust), Onyx uses overloaded procedures to provide type-specific functionality for operations such as hashing. Multiple data-structures in the `core` package need to hash a type to a 32-bit integer. `Map` and `Set` are two examples. To provide this functionality, Onyx uses an overloaded procedure called `hash` in the `core.hash` package. This example shows how to define how a `Point` structure can be hashed into a `u32`.
Overloaded procedures provide the backbone for type-generic "traits" in Onyx. Instead of making a type/object oriented system (e.g., Rust), Onyx uses overloaded procedures to provide type-specific functionality for operations such as hashing. Multiple data-structures in the `core` package need to hash a type to a 32-bit integer. `Map` and `Set` are two examples. To provide this functionality, Onyx uses an overloaded procedure called `hash` in the `core.hash` package. This example shows how to define how a `Point` structure can be hashed into a `u32`.
```onyx
Point :: struct {x, y: i32}

Expand Down
4 changes: 2 additions & 2 deletions src/procedures/paramters.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Procedures can take 0 or more parameters. All parameters are passed by value. Parameters that are passed by pointer copy the pointer value, not the data where the pointer is pointing.

## Syntax
Procedure paramaters are given a name, followed by a `:`, followed by the type of that parameter. A comma (`,`) is used to delimit the different parameters.
Procedure parameters are given a name, followed by a `:`, followed by the type of that parameter. A comma (`,`) is used to delimit the different parameters.
```onyx
print_add :: (x: i32, y: i32) {
printf("{} + {} = {}\n", x, y, x + y);
Expand All @@ -22,7 +22,7 @@ print_add :: (x, y: i32) {
```

## Default values
Parameters can have default values. The default value is computed on the caller's side. This mean default values are not part of the procedures type. They are only a conveniences provided by a given procedure.
Parameters can have default values. The default value is computed on the caller's side. This means default values are not part of the procedure's type. They are only a convenience provided by a given procedure.
```onyx
print_msg_n_times :: (n: i32, msg: str = "Hello, World!") {
for n do println(msg);
Expand Down
6 changes: 3 additions & 3 deletions src/procedures/procedures.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Procedures allow the programmer to encapsulate behavior inside a reusable form.
## Syntax
Procedures in Onyx are written simply as: `(parameters) -> return_type { body }`.

Here is a simple procedures that simply prints, `Hello!`.
Here is a simple procedure that simply prints, `Hello!`.
```onyx
say_hello :: () -> void {
println("Hello!");
Expand Down Expand Up @@ -39,9 +39,9 @@ procedure_as_an_expression :: () -> void {
```

## Optional Return Type
If the procedure returns `void` (i.e. returns nothing), the return type can be completely removed.
If the procedure returns `void` (i.e., returns nothing), the return type can be completely removed.
```onyx
say_hello :: () {
println("Hello, no void!");
}
```
```
4 changes: 2 additions & 2 deletions src/procedures/quick.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ map :: (x: $T, f: (T) -> T) -> T {
return f(x);
}

// Note that the paraentheses are optional if
// Note that the parentheses are optional if
// there is only one parameter.
y := map(5, value => value + 4);
println(y);
```

You can also have a mix between quick procedures and normal procedures. This examples shows an alternative way of writing `-> #auto`.
You can also have a mix between quick procedures and normal procedures. This example shows an alternative way of writing `-> #auto`.
```onyx
// The => could be -> #auto, or -> T.
find_smallest :: (items: [] $T) => {
Expand Down
4 changes: 2 additions & 2 deletions src/structure/packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

Onyx has a relatively simple code organization system that is similar to other languages.
To organize code, Onyx has *packages*.
A package is collection of files that define the public and private symbols of the package.
To use the symbols inside of a package, each *file* it is using the package.
A package is a collection of files that define the public and private symbols of the package.
To use the symbols inside of a package, each *file* declares that it is using the package.
This is done with the `use` keyword.

Let's say we have two source files, `foo.onyx` and `bar.onyx`
Expand Down
6 changes: 3 additions & 3 deletions src/structure/structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ Onyx's compiler is very fast. While no incredibly large programs are written in

> **Note**, Onyx's compiler is currently still **single-threaded**. If and when this issue is addressed and a multi-threaded compilation model is achieved, it is not impossible to reach over *one-million lines per second*.

One large downside of partial compilation is the need to worry about, "*Did my whole project get recompiled and updated? Or am I still testing old code?*" With a poorly configured build system, it is quite easy to cause this issue, which can lead to hours of a frustrating debugging experience. This is another reason Onyx avoid partial compilation. You know for a fact every time you compile, it is a fresh build.
One large downside of partial compilation is the need to worry about, "*Did my whole project get recompiled and updated? Or am I still testing old code?*" With a poorly configured build system, it is quite easy to cause this issue, which can lead to hours of a frustrating debugging experience. This is another reason Onyx avoids partial compilation. You know for a fact every time you compile, it is a fresh build.

## Divide files into packages
In Onyx, every source file is part of a package. The package a file is part of is declared in the first source line of file.
In Onyx, every source file is part of a package. The package that a file is part of is declared in the first source line of the file.

```onyx
// There can be comments before the package declaration.
Expand All @@ -37,7 +37,7 @@ The above file declares that it is part of the `foo` package.
All symbols declared public in this file (`func` and `Struct`) are placed in public scope of `foo`.

When another file wants to use these symbols, all it has to do is `use foo`.
Then it use `foo` to access things inside of the `foo` package.
Then it uses `foo` to access things inside of the `foo` package.

```onyx
package main
Expand Down
2 changes: 1 addition & 1 deletion src/structure/use.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Use declarations

When a file wants to use code from another package, that package must be explicitly *used*.
This is done with the `use` declaration. A `use` declaration binds one or more symbols to the current scope to other items in other package. If a `use` declaration is done at the top-level, the bindings are applied at *file scope*.
This is done with the `use` declaration. A `use` declaration binds one or more symbols in the current scope to other items in another package. If a `use` declaration is done at the top-level, the bindings are applied at *file scope*.

## Simple case
The simplest `use` declaration looks like this.
Expand Down
Loading