-#load "./lib/http-server/module"
-#load "./lib/postgres/module"
-#load "./lib/postgres-orm/module"
-#load "./lib/otmp/module"
-#library_path "./bin"
+#load "./lib/packages"
#load_all "./src"
git://onyxlang.io/repo/http-server=0.1.26
git://onyxlang.io/repo/postgres-orm=0.0.25
git://onyxlang.io/repo/otmp=0.0.7
+git://onyxlang.io/repo/postgres=0.0.10
[dependency_folders]
git://onyxlang.io/repo/http-server=http-server
#inject Res {
render :: (r: &Res, template: str, vars: any) {
s := reg->render_template(template, &r.writer, .{ vars.data, vars.type });
+
+ if s != .None {
+ log(.Warning, "Template Renderer", tprintf("{}", s));
+ }
+
r->status(200 if s == .None else 400);
r->end();
}
}
@route.{.GET, "/"}
-(req: &Req, res: &Res) {
- res->render("pages/homepage", null);
-}
-
+(req: &Req, res: &Res) => res->render("pages/homepage", null);
@route.{.GET, "/ovmwasm"}
-(req: &Req, res: &Res) {
- res->render("pages/ovmwasm", null);
-}
+(req: &Req, res: &Res) => res->render("pages/ovmwasm", null);
@route.{.GET, "/docs"}
-(req: &Req, res: &Res) {
- res->render("pages/docs", null);
-}
+(req: &Req, res: &Res) => res->render("pages/docs", null);
@route.{.GET, "/docs/install"}
-(req: &Req, res: &Res) {
- res->render("pages/docs/install", null);
-}
+(req: &Req, res: &Res) => res->render("pages/docs/install", null);
+
+
+Article :: struct { name, description, path, date: str }
+news_articles: Cached_Resource([] Article);
@route.{.GET, "/news/:article"}
(req: &Req, res: &Res) {
- // TODO: Safety / error checking here
- filename := tprintf("www/news-articles/{}.html", req.url_params["article"]);
+ article := array.first(news_articles->get() ?? .[], #(it.path == req.url_params["article"]));
+ if !article do return;
+
+ filename := tprintf("www/news-articles/{}.html", article.path);
if os.file_exists(filename) {
- article := os.get_contents(filename);
- defer delete(&article);
+ contents := os.get_contents(filename);
+ defer delete(&contents);
res->render("pages/news_article", &.{
- article = article
+ article = .{ contents = contents, name = article.name }
});
} else {
@route.{.GET, "/news"}
(req: &Req, res: &Res) {
- Article :: struct { name, description, path, date: str }
- articles: [] Article;
-
- article_file := os.get_contents("www/news-articles/index.json");
- article_index, json_err := json.decode_with_error(article_file);
- if json_err->has_error() {
- res->status(500);
- return;
- }
-
- json.as_any(article_index.root, &articles);
+ articles := news_articles->get() ?? .[];
res->render("pages/news", &.{
articles = articles
reg = otmp.registry();
reg->load_directory("./www/templates", ".html");
+ news_articles = .{
+ resource = .{},
+ max_age = 60 * 60, // 1 hour
+
+ fetch_resource = () -> ? [] Article {
+ article_file := os.get_contents("www/news-articles/index.json");
+ article_index, json_err := json.decode_with_error(article_file);
+ if json_err->has_error() {
+ return .{};
+ }
+
+ articles: [] Article;
+ #context_scope {
+ context.allocator = alloc.heap_allocator;
+ json.as_any(article_index.root, &articles);
+ }
+ return articles;
+ },
+
+ release_resource = (articles: &[] Article) {
+ delete(articles, allocator=alloc.heap_allocator);
+ }
+ };
+
app := http.server.application();
http.server.set_mime_type("svg", "image/svg+xml");
--- /dev/null
+package main
+
+use core {package, tprintf}
+use core.time
+
+Cached_Resource :: struct (Res: type_expr) {
+ last_retrieved: time.Timestamp;
+ max_age: i32; // In seconds
+
+ resource: ? Res;
+ fetch_resource: () -> ? Res;
+ release_resource: (res: &Res) -> void;
+}
+
+#inject Cached_Resource {
+ get :: (use self: &#Self) -> ? self.Res {
+ if !resource {
+ update_resource(self);
+ }
+
+ if time.duration(time.now(), last_retrieved) > max_age {
+ update_resource(self);
+ }
+
+ return self.resource;
+ }
+}
+
+#local
+update_resource :: (self: &Cached_Resource($T)) {
+ if self.resource {
+ self.release_resource(&self.resource.value);
+ self.resource->reset();
+ }
+
+ self.resource = self.fetch_resource();
+ self.last_retrieved = time.now();
+}
+
+
+
+#inject time {
+ duration :: (t2, t1: time.Timestamp) -> i32 {
+ t1_ := t1;
+ t2_ := t2;
+ return ~~(t2_->to_epoch() - t1_->to_epoch());
+ }
+}
+
[
+ {
+ "name": "Onyx's Memory Model",
+ "path": "memory_model",
+ "date": "29th April 2023",
+ "description": "A explanation of the memory model employed by Onyx."
+ },
{
"name": "Onyx's Custom Runtime",
"path": "ovmwasm",
"date": "5th April 2023",
- "description": "Something about a brief introduction to the OVM-Wasm system."
+ "description": "A brief introduction to OVM-Wasm, Onyx's custom WASM runtime for debugging and portability."
}
]
--- /dev/null
+<h1>Onyx's Memory Model</h1>
+
+<p>
+When choosing and/or learning a programming language, the memory model is one of the first things you will have to understand to successfully use the language.
+In broad terms, there are three memory models employed in programming languages used today: <i>manual, manual with assistance, and automatic.</i>
+</p>
+
+<p>
+In a <i>manual</i> memory model, almost all memory allocations and deallocations are done, well, manually.
+You, the programmer, are responsible for diligently freeing <i>every</i> piece of memory you allocate; otherwise, over time, your program's memory usage will increase and start consuming a lot of system resources.
+</p>
+<blockquote>
+ Do note, that this only applies to programs that run for a long time, or need to work with a lot of resources.
+ Forgetting to free a 100 element array in your small 10 line program is not going to be the end of the world.
+ The operating system is responsible for reclaiming all resources your program used when your program exits.
+</blockquote>
+
+<p>
+In an <i>automatic</i> memory model, you are not responsible for managing any allocation made by your program.
+Programming languages with this memory model generally employ a garbage collector or reference counted pointers.
+</p>
+
+<p>
+The third and final memory model is <i>manual with assistance</i>, which is the memory model that Onyx uses.
+This model trusts the programmer to understand their memory needs, allowing total control over memory.
+However, it also offers core library support for describing the memory model.
+</p>
+
+<h2>Allocators</h2>
+
+<p>
+Onyx abstracts the notion of memory management into an <i>Allocator</i>.
+Anything that requires allocating memory should consume an Allocator as a parameter.
+This is the pattern followed by everything in the core library; all memory allocations are configurable.
+Also as a convience, the default allocator used by the core library is <code>context.allocator</code>.
+This is a thread-local variable that is a general purpose heap allocator by default, but can be changed.
+This allows for changing the allocator used by a library even if the library does not take an allocator as a paramter.
+</p>
+
+<p>
+Most programmers will not have to write their own allocator.
+Instead they will use one of half-dozen provided out of the box by the core libraries.
+</p>
+
+<h3>Heap Allocator</h3>
+<p>
+In every Onyx program, there is a single general purpose heap allocator.
+It can be accessed in <code>core.alloc.heap_allocator</code>.
+It is automatically setup before your program reaches <code>main</code>.
+It is also the default allocator used by <code>context.allocator</code>, meaning functions like <code>new</code>, <code>make</code>, and <code>calloc</code> will use it by default.
+</p>
+
+<blockquote>
+While Onyx has its own heap allocation procedures, the heap allocator is effectively equivalent to C's <code>malloc</code> and <code>free</code>.
+You are responsible for manually freeing the memory allocated from it.
+</blockquote>
+
+<p>
+Here is an example of using the heap allocator directly.
+</p>
+
+<pre class="hljs"><code class="language-onyx">use core {*}
+
+main :: () {
+ // Directly allocate an array of 10 u32's.
+ data := cast([&] u32) alloc.heap_allocator->alloc(sizeof u32 * 10);
+
+ // Ensure the memory is freed when the function returns.
+ defer alloc.heap_allocator->free(data);
+
+ // Fill the array with squares
+ for 10 {
+ data[it] = it * it;
+ }
+
+ // Print out the array
+ for 10 {
+ println(data[it]);
+ }
+}
+</code></pre>
+
+
+<h3>Arena Allocator</h3>
+
+<p>
+While the general purpose heap allocator will work in any situation, it is not the fastest.
+Also, it requires you to correctly manage the memory allocated from it, which can be error prone.
+</p>
+
+
font-weight: 200;
}
+.container h2 {
+ margin-top: 16px;
+}
+
.container h3 {
margin-top: 12px;
}
display: block;
}
+main blockquote {
+ border-left: 4px solid var(--dark-background-color);
+ background-color: var(--light-background-color);
+ margin-top: 12px;
+ padding: 8px;
+}
+
main li {
margin-top: 8px;
}
+{{block "title"}}Onyx - Page not found{{endblock}}
+
{{block "content"}}
<main>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="The Onyx programming language, by Brendan Hansen.">
+ <link rel="icon" type="image/x-icon" href="/static/images/favicon.ico">
<link rel="stylesheet" href="/static/css/new_style.css">
<!-- Including this on every page because why not -->
+{{block "title"}}Onyx Documentation{{endblock}}
+
{{block "page_content"}}
<div class="container">
+{{block "title"}}Onyx Installation{{endblock}}
+
{{ block "page_content" }}
<div class="container">
+{{block "title"}}The Onyx Programming Language{{endblock}}
+
{{block "page_content"}}
<div class="container center" style="margin: 0 auto">
+{{block "title"}}Onyx News{{endblock}}
+
{{block "page_content"}}
<div class="container">
+{{block "title"}}Onyx News - {% $article.name %}{{endblock}}
+
{{block "content"}}
<main>
{% partial "partials/navbar" %}
<div class="container">
- {% $article %}
+ {% $article.contents %}
</div>
{% partial "partials/footer" %}