}
}
+lsp {
+ mode "project"
+ source_files "build.onyx"
+ include_dirs ""
+ working_dir "."
+}
+
});
}
+@route.{.GET, "/examples"}
+(req: &Req, res: &Res) {
+ exs := examples->get() ?? .[];
+
+ res->render("pages/examples", &.{
+ examples = exs
+ });
+}
+
main :: () {
default_log_level(.Error);
load_library_list();
}
};
+ examples = .{
+ resource = .{},
+ max_age = 60 * 60 * 24, // 1 day
+ fetch_resource = load_examples,
+ release_resource = delete_examples,
+ };
+
http.server.set_mime_type("svg", "image/svg+xml");
pipes := http.server.pipeline();
url, name, description: str;
}
+Example :: struct {
+ name, code, html: str;
+}
+
#local {
core_packages: [] Package;
third_party_packages: [] Package;
+
+ examples: Cached_Resource([] Example);
}
load_library_list :: () {
slice.sort(third_party_packages, (a, b) => string.compare(a.name, b.name));
}
+
+load_examples :: () -> ? [] Example {
+ #context_scope {
+ context.allocator = alloc.heap_allocator;
+
+ examples: [] Example;
+
+ os.get_contents("www/examples/index.json")
+ |> json.decode_into(&examples);
+
+ for &example in examples {
+ code_path := os.path_join("www/examples", example.code);
+ html_path := os.path_join("www/examples", example.html);
+
+ example.code = os.get_contents(code_path);
+ example.html = os.get_contents(html_path);
+ }
+
+ return examples;
+ }
+}
+
+delete_examples :: (exs: &[] Example) do #context_scope {
+ context.allocator = alloc.heap_allocator;
+
+ for &ex in *exs {
+ delete(&ex.code);
+ delete(&ex.html);
+ }
+
+ delete(exs);
+}
+
--- /dev/null
+<p>
+ This example shows three different ways to do the same thing: compute Fibonacci numbers.
+</p>
--- /dev/null
+use core.iter
+use core { printf }
+
+//
+// Way number 1: A simple for-loop
+// This method simply uses a for-loop like you would in C to generate
+// the Fibonacci numbers. No tricks to it.
+//
+fib_for_loop :: (n: i32) -> u64 {
+ a: u64 = 0;
+ b: u64 = 1;
+
+ for 0 .. n {
+ tmp := a;
+ a = b;
+ b = tmp + b;
+ }
+
+ return a;
+}
+
+//
+// Way number 2: Functional folding
+// This way creates an iterator that will yield n integers, thats the
+// iter.counter piped to iter.take(n). Then, for each one of those numbers
+// it steps the state, computing the Fibonacci numbers in the process.
+// The final result is the "a" member of the final state.
+
+FibState :: struct { a, b: u64 }
+
+fib_by_fold :: (n: i32) => {
+ end_state :=
+ // This creates an infinite iterator that simply counts up from 0.
+ iter.counter()
+
+ // This limits only taking the first n values.
+ |> iter.take(n)
+
+ // This performs a "fold" or "reduce" operation.
+ |> iter.fold(
+ // This defines the initial accumulator state.
+ FibState.{ a = 0, b = 1 },
+
+ // This defines the "folding" function. It takes the next value
+ // from the iterator, which we simply ignore because we do not
+ // need it, and the previous value of the accumulator. It then
+ // computes and returns the next value for the accumulator.
+ // iter.fold returns the final value of the accumulator.
+ (_, state) => FibState.{
+ a = state.b,
+ b = state.a + state.b
+ }
+ );
+
+ return end_state.a;
+}
+
+
+//
+// Way number 3: A custom iterator
+// This way produces an iterator that yields consecutive Fibonacci numbers.
+// This is slightly faster than the previous methods because it does not have
+// to redo all the work for every query.
+//
+
+fib_iterator :: (n: i32) =>
+ // This is implemented using a generator, which is a custom iterator
+ // that yields values according to the "next" function defined below.
+ iter.generator(
+ // The initial state of the generator.
+ &.{ a = cast(u64) 0, b = cast(u64) 1, counter = n },
+
+ // The generation function. This takes in a pointer to the state
+ // and must return 2 things: the next value and a boolean of whether
+ // to continue or not.
+ //
+ // Notice that the parameter's type is a polymorphic here; notice the $.
+ // This is because the above structure literal is entirely type infered;
+ // no explicit type was given to it. Therefore, there is no type we can
+ // write here that would be correct. We could make a structure for it,
+ // but in this case it is fine to let the compiler do a little magic.
+ (state: & $Ctx) -> (u64, bool) {
+ if state.counter <= 0 {
+ return 0, false;
+ }
+
+ tmp := state.a;
+ state.a = state.b;
+ state.b = state.b + tmp;
+
+ state.counter -= 1;
+ return tmp, true;
+ }
+ );
+
+
+main :: () {
+ // Print the results from fib_for_loop
+ for i in 0 .. 90 {
+ printf("{}: {}\n", i, fib_for_loop(i));
+ }
+
+ // Print the results from fib_by_fold
+ for i in 0 .. 90 {
+ printf("{}: {}\n", i, fib_by_fold(i));
+ }
+
+ // Print the results from fib_iterator
+ for value, index in fib_iterator(90) {
+ printf("{}: {}\n", index, value);
+ }
+}
+
--- /dev/null
+<p>
+ This example shows various ways of reading and writing to a file.
+ The core idea behind files in Onyx is that they extend the <code>io.Stream</code> structure, so you can use the <code>core.io</code> package to interact with them.
+</p>
--- /dev/null
+use core.os
+use core.io
+use core.string
+use core {
+ printf
+}
+
+#doc "Writes example text into a file."
+write_data_into_file :: (filename: str) {
+ // This is one way of opening a file: call os.open and then os.close later.
+ // os.open returns a Result(os.File, os.FileError), so it must be handled
+ // to use the os.File. This program opts to unwrap the result.
+ file := os.open(filename, .Write)->unwrap();
+ defer os.close(&file);
+
+ // Create an io.Writer over the file stream using io.writer_make.
+ // Also, free it later by defering io.writer_free. This also flushes
+ // the internal buffer of io.Writer to make sure everything is written
+ // to the file.
+ file_writer := io.writer_make(&file);
+ defer io.writer_free(&file_writer);
+
+ // The simplest way of writing a string to the file.
+ io.write(&file_writer, "This is the first line of text.\n");
+
+ // io.write_format can be used to "printf" into a file.
+ // printf can be thought of as io.write_format(&stdio.stream, ...).
+ io.write_format(&file_writer, "This is a {} line of text.\n", "formatted");
+
+ for i in 0 .. 5 {
+ io.write_format(&file_writer, "Another line numbered {}.\n", i);
+ }
+}
+
+#doc "Reads example text from a file."
+read_data_from_file :: (filename: str) {
+ // This is another way of opening a file. Because of the semantics
+ // of `for` loops over Iterators, they can behave like `with`
+ // statements in Python or `using` statements in C#.
+ for file in os.with_file(filename, .Read) {
+ // Create a io.Reader over the file stream.
+ file_reader := io.reader_make(file);
+ defer io.reader_free(&file_reader);
+
+ // Read a single line.
+ first_line := io.read_line(&file_reader);
+ printf("First line: {}\n", first_line);
+
+ // Use io.lines to create an iterator over the remaining
+ // lines in the file.
+ printf("Remaining lines:\n");
+ for line, index in io.lines(&file_reader) {
+ printf("{}: {}\n", index, line);
+ }
+ }
+}
+
+#doc "Reads example text from a file."
+read_whole_file :: (filename: str) {
+ // This is the simplest way to get the entire content of a file
+ // into a string ([] u8). Also, defer "deleting" the string, which
+ // will free the memory allocated for the string.
+ contents := os.get_contents(filename);
+ defer delete(&contents);
+
+ printf("Whole contents:\n{}\n", contents);
+}
+
+main :: () {
+ filename := "test.txt";
+
+ write_data_into_file(filename);
+ read_data_from_file(filename);
+ read_whole_file(filename);
+}
+
--- /dev/null
+[
+ {
+ "name": "Reading from standard input",
+ "code": "stdin.onyx",
+ "html": "stdin.html"
+ },
+ {
+ "name": "Interact with files",
+ "code": "files.onyx",
+ "html": "files.html"
+ },
+ {
+ "name": "Fibonacci printer",
+ "code": "fib.onyx",
+ "html": "fib.html"
+ }
+]
+
+
--- /dev/null
+This example reads a single line of input from <a href="https://en.wikipedia.org/wiki/Standard_streams">standard input</a>, splits it in half on the first space using <a href="https://docs.onyxlang.io/packages/core.string.html#bisect">string.bisect</a>, converts both parts to integers using <a href="https://docs.onyxlang.io/packages/core.conv.html#parse">conv.parse</a>, then prints the results using <a href="https://docs.onyxlang.io/packages/core.html#printf">printf</a> for formatted printing.
--- /dev/null
+// Use the necessary core libraries
+use core.io
+use core.string
+use core.conv
+
+// Use the printf function that lives in the core package.
+// This cannot be `use core.printf`, because that will look
+// for a package called `printf` in `core`.
+use core {
+ printf
+}
+
+main :: () {
+ // Create a io.Reader over the stdio.stream to be able scan
+ // the input in parts. Also, defer freeing the reader until
+ // the end of `main`.
+ stdin_reader := io.reader_make(&stdio.stream);
+ defer io.reader_free(&stdin_reader);
+
+ // Read a single line of input.
+ line := io.read_line(&stdin_reader);
+
+ // Split the line on the first space.
+ a_str, b_str := string.bisect(line, " ");
+
+ // Parse and convert both parts to i32s, with a default value
+ // of 0 if it fails to parse as an i32.
+ a_value := conv.parse(i32, a_str)->value_or(0);
+ b_value := conv.parse(i32, b_str)->value_or(0);
+
+ // Compute our result.
+ result := a_value + b_value;
+
+ // Output our result using formatted printing.
+ printf("{} + {} = {}\n", a_value, b_value, result);
+}
--accent-text: #000000;
}
-@media (min-width: 800px) {
+@media (min-width: 900px) {
:root {
--default-flex-direction: row;
font-size: 14pt;
}
}
-@media (max-width: 799px) {
+@media (max-width: 899px) {
:root {
--default-flex-direction: column;
font-size: 10pt;
background-position: bottom;
}
-@media screen and (min-width: 800px) {
+@media screen and (min-width: 900px) {
.container .split {
display: flex;
flex-direction: row;
}
}
-@media screen and (max-width: 799px) {
+@media screen and (max-width: 899px) {
.container .split {
display: flex;
flex-direction: column;
/* Navigation */
-@media screen and (min-width: 800px) {
+@media screen and (min-width: 900px) {
.navbar-container {
position: relative;
background: none;
}
}
-@media screen and (max-width: 799px) {
+@media screen and (max-width: 899px) {
.navbar-container {
position: relative;
background: none;
border-bottom: none;
}
-@media (min-width: 800px) {
- #mobile-hamburger, .hamburger-piece {
+@media (min-width: 900px) {
+ #mobile-hamburger, span.hamburger {
display: none;
}
}
-@media (max-width: 799px) {
+@media (max-width: 899px) {
navbar div {
display: none;
}
margin-top: 24px;
}
-@media (min-width: 800px) {
+@media (min-width: 900px) {
#desktop_logo {
position: relative;
top: 6px;
#homepage-logo:hover #path274 { transform: matrix(0.307405,0,0,0.303728,34.782897,16.545361); }
#homepage-logo:hover #path67 { opacity: 0; transform: matrix(0.14795386,0,0,0.14795386,100.382719,-1000.6710591); }
-@media (max-width: 799px) {
+@media (max-width: 899px) {
#mobile_logo {
position: relative;
top: 6px;
opacity: 1;
}
-@media screen and (min-width: 800px) {
+@media screen and (min-width: 900px) {
#install-card {
width: 800px;
}
position: relative;
}
+.scrollport > * {
+ margin-top: 6em;
+}
+
/*
@media screen and (min-width: 800px) {
.scrollport {
# Install the LSP (compiles and places the WASM file into $ONYX_PATH/tools)
./install.sh</code></pre>
+ <p>On Windows, run the following commands.</p>
+ <pre class="hljs"><code class="language-bat">REM Clone the Onyx Language Server
+git clone https://github.com/onyx-lang/onyx-lsp
+cd onyx-lsp
+REM Install the LSP (compiles and places the WASM file into %ONYX_PATH%/tools)
+install.bat</code></pre>
+
<h3>Visual Studio Code</h3>
<p>Installing the extension automatically enables the language server in VS Code.</p>
<p>Create a new directory and setup a new project. Optionally project values when prompted.</p>
<pre class="hljs"><code class="language-sh">$ mkdir my-onyx-project
$ cd my-onyx-project
-$ onyx pkg init
+$ onyx package init
Creating new project manifest in ./onyx-pkg.kdl.
Package name: my-onyx-project
--- /dev/null
+{{ block "title" }}
+Onyx Examples
+{{ endblock }}
+
+{{ let navbar_page = "examples" }}
+
+{{ block "page_content" }}
+
+<div class="container header">
+ <h1>Onyx Examples</h1>
+ <p>This page provides several simple examples of Onyx code, showing how to do common things with the standard library.</p>
+</div>
+
+{{ foreach ex in examples }}
+<div class="container">
+ <div class="title">
+ <h2>{% ex.name %}</h2>
+ </div>
+
+ <div>
+ {% ex.html %}
+ </div>
+
+ <pre class="hljs"><code class="language-onyx">{% ex.code %}</code></pre>
+</div>
+{{ endforeach }}
+
+<div class="container">
+ <div class="title">
+ <h2>Want to learn more?</h2>
+ </div>
+ <p>
+ <a class="link-button" href="/docs">Visit the docs!</a>
+ </p>
+ <p>
+ You can learn more details about Onyx by visiting the docs!
+ There is more examples, a reference manual for the language, and documentation for the standard library.
+ </p>
+</div>
+
+{{ endblock }}
+
+{{ extends "pages/normal_page" }}
+
<span class="copy-button">Copy</span>
</div>
<div><span style="color: #444;">$</span> <span style="font-style: italic; color: #99a;"># Read the docs</span></div>
- <div><span style="color: #444;">$</span> <span style="color: var(--accent)">curl</span> <a style="text-decoration: underline" href="/docs">onyxlang.io/docs</a></div>
+ <div><span style="color: #444;">$</span> <span style="color: var(--accent)">curl</span> <a href="/docs">onyxlang.io/docs</a></div>
<div><span style="color: #444;">$</span> <span style="font-style: italic; color: #99a;"># Try Onyx in your browser</span></div>
- <div><span style="color: #444;">$</span> <span style="color: var(--accent)">curl</span> <a style="text-decoration: underline" href="https://try.onyxlang.io/">try.onyxlang.io</a></div>
+ <div><span style="color: #444;">$</span> <span style="color: var(--accent)">curl</span> <a href="https://try.onyxlang.io/">try.onyxlang.io</a></div>
</div>
</div>
</div>
msg: [] u8 = "Hello, libc!";
write(1, msg.data, msg.length);
-}
- </code></pre>
+}</code></pre>
+</div>
+
+<div>
+ <div>
+ <h2>More examples</h2>
+ <br />
+ <p>See more complete examples on the <a href="/examples">Examples</a> page.</p>
+ </div>
</div>
</div>
{{ endif }}
<div class="navbar-container">
- <navbar>
+ <navbar
+ {{ if homepage == true }} style="justify-content: center" {{ endif }}
+ >
{{ if homepage == false }}
<a href="/" aria-label="Go to the homepage">
<svg viewBox="0 0 64 16" version="1.1" id="desktop_logo" alt="Onyx Logo">