build/onyxmsgs.o \
build/onyxutils.o \
build/onyxwasm.o \
+ build/onyxdoc.o \
build/onyx.o
CC=gcc
context : struct {
allocator : Allocator;
- temp_allocator : Allocator;
+ temp_allocator : Allocator;
}
\ No newline at end of file
seed := 8675309
random_seed :: proc (s: u32) do seed = s;
-random :: proc -> u32 {
- seed = seed * 5831 + 102847;
- return seed;
+random :: proc (s := ^seed) -> u32 {
+ *s = *s * 5831 + 102847;
+ return *s;
}
random_between :: proc (lo: i32, hi: i32) -> i32 do return random() % (hi + 1 - lo) + lo;
\ No newline at end of file
string_free :: proc (a: Allocator, s: string) do free(a, s.data);
+// This is an example doc string
+// You can have as many comments as you want
+// It documents the string_split function
string_split :: proc (a: Allocator, str: string, delim: u8) -> []string {
delim_count := 0;
for i: 0, str.count do if str.data[i] == delim do delim_count += 1;
package wasi
use package main as main
-use package builtin { string }
+use package builtin
use package memory
Size :: #type u32;
proc #export "_start" {
memory_init();
+ context.allocator = heap_allocator;
+ context.temp_allocator = heap_allocator;
+
argc : Size;
argv_buf_size : Size;
--- /dev/null
+ The Onyx Standard Library
+---------------------------------------------------------------------------
+
+Through Onyx has only one compilation target, WebAssembly 32-bit, there are
+fundamentally two different use cases: in a browser, or with WASI. Both of
+these use cases are to be treated as equally important. To accommodate for
+their very different runtimes, a common standard library must be established
+that they can share the functionality.
+
+The standard high level topics to cover are:
+ - standard output
+ - allocation
+ - standard math functions
+ - strings
+ - files
+ - utility functions
+ * random
+ * clock
+
+
+
+
+
+
+
+
+Package main:
+ main :: proc (args: [] cstring) -> i32
+
+Package string:
+ string_split :: proc (a: Allocator, s: string, delim: u8) -> [] string
+ at /usr/share/onyx/core/string.onyx:50,0
+ Auto documentation for string_split
[X] default parameters
- Must be the last parameters
+ [X] Basic documentation outputter
+
[ ] #file and #line directives
- string and u32 respectively that represent the current file and line number where the directive is
- struct member names
- array length
+ [ ] Clean up error messages
+ - Stop using Msg_Type_Literal everywhere and be more specific
+
[ ] 'use' enums and packages at an arbitrary scope
[ ] convert to using an 'atom' like table
--- /dev/null
+#ifndef ONYXDOC_H
+#define ONYXDOC_H
+
+#include "bh.h"
+#include "onyxastnodes.h"
+
+typedef struct DocEntry {
+ OnyxFilePos pos;
+ char* def;
+ char* additional;
+} DocEntry;
+
+typedef struct DocPackage {
+ const char* name;
+
+ bh_arr(DocEntry) public_entries;
+ bh_arr(DocEntry) private_entries;
+} DocPackage;
+
+typedef struct OnyxDocumentation {
+ bh_arena doc_arena;
+
+ bh_arr(DocPackage) package_docs;
+} OnyxDocumentation;
+
+OnyxDocumentation onyx_docs_generate(ProgramInfo* prog);
+void onyx_docs_write(OnyxDocumentation* doc);
+
+#endif
\ No newline at end of file
use package memory
use package wasi
use package intrinsics
+use package random
-print_u64_with_base :: proc (n_: u64, base := 10l) {
+print_u64 :: proc (n_: u64, base := 10l) {
n := n_;
str: [256] u8;
for i: 0, 256 do str[i] = #char "\0";
print :: proc #overloaded { print_string, print_u8 }
print_rights :: proc (rights: Rights) {
- print_u64_with_base(cast(u64) rights, 2l);
+ print_u64(cast(u64) rights, 2l);
print("\n");
if rights & Rights.DataSync != cast(Rights) 0 do print("DataSync\n");
print("\n");
print("\td_namlen: ");
- print_u64_with_base(cast(u64) dirent.d_namlen, 16l);
+ print_u64(cast(u64) dirent.d_namlen, 16l);
print("\n");
print("\td_type: ");
- print_u64_with_base(cast(u64) dirent.d_type, 16l);
+ print_u64(cast(u64) dirent.d_type, 16l);
print("\n");
bufused -= sizeof DirEnt + dirent.d_namlen;
}
main :: proc (args: []cstring) {
+ now : Timestamp;
+ clock_time_get(ClockID.Realtime, cast(Timestamp) 1, ^now);
+
+ random_seed(cast(u32) now);
+
sb := string_builder_make(heap_allocator, 256);
timer := timer_start();
if err := path_open(3, LookupFlags.SymLinkFollow, string_make(args.data[1]), cast(OFlags) 0, Rights.DataSync | Rights.Write | Rights.Read | Rights.Tell | Rights.Seek | Rights.Advise | Rights.PathOpen | Rights.PathCreateFile, Rights.DataSync | Rights.Write | Rights.Read | Rights.Tell | Rights.Seek | Rights.Advise | Rights.PathOpen | Rights.PathCreateFile, FDFlags.Sync, ^fd); err != Errno.Success {
print("Failed to open file\n");
print("Error code: ");
- print_u64_with_base(cast(u64) err, 16l);
+ print_u64(cast(u64) err, 16l);
proc_exit(1);
}
defer fd_close(fd);
- print_u64_with_base(cast(u64) fd, 16l);
+ print_u64(cast(u64) fd, 16l);
print("\n");
filelen : Filesize;
proc_exit(1);
}
print("the size is: ");
- print_u64_with_base(cast(u64) filelen);
+ print_u64(cast(u64) filelen);
print("\n");
sum := 0l;
for i: 0, 20000 do if is_prime(i) do sum += cast(u64) i;
print("Sum of primes less than 20000 is: ");
- print_u64_with_base(sum);
+ print_u64(sum);
print("\n");
matches := string_split(heap_allocator, "This is a test string to test splitting. It surprisingly works very well.", #char " ");
case #default {
print("Unexpected token: ");
- print_u64_with_base(cast(u64) tokens.data[i].data[0], 16l);
+ print_u64(cast(u64) tokens.data[i].data[0], 16l);
print("\n");
// This breaks out of the for loop
foobar(10, 1230);
sl := make_i32_arr();
- print_u64_with_base(cast(u64) sl.count);
+ print_u64(cast(u64) sl.count);
}
foobar :: proc (a: i32, b := 1, c := 5l) {
- print_u64_with_base(cast(u64) a);
+ print_u64(cast(u64) a);
print("\n");
- print_u64_with_base(cast(u64) b, 16l);
+ print_u64(cast(u64) b, 16l);
print("\n");
- print_u64_with_base(c);
+ print_u64(c);
print("\n");
}
\ No newline at end of file
#include "onyxsempass.h"
#include "onyxutils.h"
#include "onyxwasm.h"
+#include "onyxdoc.h"
#define VERSION "0.1"
"The compiler for the Onyx programming language.\n"
"\n"
"Usage:\n"
- "\tonyx [-o <target file>] [-ast] [-verbose] <input files>\n"
+ "\tonyx [-o <target file>] [-verbose] <input files>\n"
+ "\tonyx doc <input files>\n"
"\tonyx -help\n"
"\nFlags:\n"
"\t-o <target_file> Specify the target file (default: out.wasm)\n"
typedef enum CompileAction {
ONYX_COMPILE_ACTION_COMPILE,
- ONYX_COMPILE_ACTION_CHECK_ERRORS,
+ ONYX_COMPILE_ACTION_DOCUMENT,
ONYX_COMPILE_ACTION_PRINT_HELP,
} CompileAction;
CompileAction action;
u32 verbose_output : 1;
- u32 print_ast : 1;
bh_arr(const char *) included_folders;
bh_arr(const char *) files;
.action = ONYX_COMPILE_ACTION_PRINT_HELP,
.verbose_output = 0,
- .print_ast = 0,
.files = NULL,
.target_file = "out.wasm",
bh_arr_push(options.included_folders, ".");
fori(i, 1, argc) {
- if (!strcmp(argv[i], "-help")) {
+ if (!strcmp(argv[i], "doc") && i == 1) {
+ options.action = ONYX_COMPILE_ACTION_DOCUMENT;
+ }
+ else if (!strcmp(argv[i], "-help")) {
options.action = ONYX_COMPILE_ACTION_PRINT_HELP;
break;
}
else if (!strcmp(argv[i], "-o")) {
- options.action = ONYX_COMPILE_ACTION_COMPILE;
options.target_file = argv[++i];
}
- else if (!strcmp(argv[i], "-ast")) {
- options.print_ast = 1;
- }
else if (!strcmp(argv[i], "-verbose")) {
options.verbose_output = 1;
}
else if (!strcmp(argv[i], "-I")) {
- options.action = ONYX_COMPILE_ACTION_COMPILE;
bh_arr_push(options.included_folders, argv[++i]);
}
else {
- options.action = ONYX_COMPILE_ACTION_COMPILE;
+ if (options.action == ONYX_COMPILE_ACTION_PRINT_HELP)
+ options.action = ONYX_COMPILE_ACTION_COMPILE;
+
bh_arr_push(options.files, argv[i]);
}
}
return ONYX_COMPILER_PROGRESS_FAILED_SEMPASS;
}
+ if (compiler_state->options->action == ONYX_COMPILE_ACTION_DOCUMENT) {
+ OnyxDocumentation docs = onyx_docs_generate(&compiler_state->prog_info);
+ onyx_docs_write(&docs);
+
+ return ONYX_COMPILER_PROGRESS_SUCCESS;
+ }
// NOTE: Generate WASM instructions
if (compiler_state->options->verbose_output)
return 1;
case ONYX_COMPILE_ACTION_COMPILE:
+ case ONYX_COMPILE_ACTION_DOCUMENT:
compiler_progress = onyx_compile(&compile_state);
break;
--- /dev/null
+#include "onyxdoc.h"
+#include "onyxutils.h"
+#include "onyxtypes.h"
+
+static i32 cmp_doc_entry(const void * a, const void * b) {
+ DocEntry* d1 = (DocEntry *) a;
+ DocEntry* d2 = (DocEntry *) b;
+
+ return strncmp(d1->def, d2->def, 1024);
+}
+
+static i32 cmp_doc_package(const void * a, const void * b) {
+ DocPackage* d1 = (DocPackage *) a;
+ DocPackage* d2 = (DocPackage *) b;
+
+ return strncmp(d1->name, d2->name, 1024);
+}
+
+static char* node_to_doc_def(const char* sym, AstNode *node, bh_allocator a) {
+ static char buf[1024];
+ memset(buf, 0, 1023);
+
+ strncat(buf, sym, 1023);
+ strncat(buf, " :: ", 1023);
+
+ switch (node->kind) {
+ case Ast_Kind_Function: {
+ strncat(buf, "proc (", 1023);
+
+ AstFunction *func = (AstFunction *) node;
+ bh_arr_each(AstParam, param, func->params) {
+ if (param != func->params)
+ strncat(buf, ", ", 1023);
+
+ token_toggle_end(param->local->token);
+ strncat(buf, param->local->token->text, 1023);
+ token_toggle_end(param->local->token);
+
+ strncat(buf, ": ", 1023);
+
+ strncat(buf, type_get_name(param->local->type), 1023);
+
+ if (param->default_value != NULL) {
+ strncat(buf, " = <default>", 1023);
+ }
+ }
+
+ strncat(buf, ")", 1023);
+
+ if (func->type->Function.return_type != &basic_types[Basic_Kind_Void]) {
+ strncat(buf, " -> ", 1023);
+ strncat(buf, type_get_name(func->type->Function.return_type), 1023);
+ }
+
+ break;
+ }
+
+ case Ast_Kind_Struct_Type: {
+ strncat(buf, "struct { ", 1023);
+
+ AstStructType* st = (AstStructType *) node;
+ bh_arr_each(AstStructMember *, smem, st->members) {
+
+ token_toggle_end((*smem)->token);
+ strncat(buf, (*smem)->token->text, 1023);
+ token_toggle_end((*smem)->token);
+
+ strncat(buf, ": ", 1023);
+
+ strncat(buf, type_get_name((*smem)->type), 1023);
+
+ strncat(buf, "; ", 1023);
+ }
+
+ strncat(buf, "}", 1023);
+ break;
+ }
+
+ case Ast_Kind_Basic_Type:
+ case Ast_Kind_Array_Type:
+ case Ast_Kind_Type_Alias:
+ case Ast_Kind_Slice_Type: {
+ strncat(buf, type_get_name(type_build_from_ast(global_heap_allocator, (AstType *) node)), 1023);
+ break;
+ }
+
+ default: {
+ strncat(buf, "<unimplemented printing>", 1023);
+ }
+ }
+
+ return bh_strdup(a, buf);
+}
+
+static DocPackage doc_package_create(Package* p, bh_allocator a) {
+ DocPackage dp;
+ dp.name = p->name;
+ dp.public_entries = NULL;
+ dp.private_entries = NULL;
+
+ bh_arr_new(global_heap_allocator, dp.public_entries, 16);
+ bh_arr_new(global_heap_allocator, dp.private_entries, 16);
+
+ bh_table_each_start(AstNode *, p->scope->symbols)
+ DocEntry de;
+ de.pos = value->token->pos;
+ de.def = node_to_doc_def(key, value, a);
+ de.additional = NULL;
+
+ bh_arr_push(dp.public_entries, de);
+ bh_table_each_end;
+
+ bh_table_each_start(AstNode *, p->private_scope->symbols)
+ DocEntry de;
+ de.pos = value->token->pos;
+ de.def = node_to_doc_def(key, value, a);
+ de.additional = NULL;
+
+ bh_arr_push(dp.private_entries, de);
+ bh_table_each_end;
+
+ qsort(dp.public_entries, bh_arr_length(dp.public_entries), sizeof(DocEntry), cmp_doc_entry);
+ qsort(dp.private_entries, bh_arr_length(dp.private_entries), sizeof(DocEntry), cmp_doc_entry);
+
+ return dp;
+}
+
+OnyxDocumentation onyx_docs_generate(ProgramInfo* prog) {
+ OnyxDocumentation doc;
+
+ bh_arena_init(&doc.doc_arena, global_heap_allocator, 16 * 1024);
+ bh_allocator a = bh_arena_allocator(&doc.doc_arena);
+
+ doc.package_docs = NULL;
+ bh_arr_new(global_heap_allocator, doc.package_docs, 16);
+
+ bh_table_each_start(Package *, prog->packages);
+ DocPackage dp = doc_package_create(value, a);
+ bh_arr_push(doc.package_docs, dp);
+ bh_table_each_end;
+
+ qsort(doc.package_docs, bh_arr_length(doc.package_docs), sizeof(DocPackage), cmp_doc_package);
+
+ return doc;
+}
+
+void onyx_docs_write(OnyxDocumentation* doc) {
+ // NOTE: Disabling fancy line printing until I can make it better
+ #if 0
+ bh_arr_each(DocPackage, dp, doc->package_docs) {
+ bh_printf("Package '%s'\n", dp->name);
+
+ if (bh_arr_length(dp->public_entries) > 0) {
+ bh_printf("\xe2\x94\x9c\xe2\x94\x80 Public symbols\n");
+ bh_arr_each(DocEntry, de, dp->public_entries) {
+ bh_printf("\xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80 %s\n", de->def);
+
+ if (de->pos.filename != NULL)
+ bh_printf("\xe2\x94\x82 \xe2\x94\x82 at %s:%d,%d\n", de->pos.filename, de->pos.line, de->pos.column);
+ else
+ bh_printf("\xe2\x94\x82 \xe2\x94\x82 compiler built-in\n");
+
+ bh_printf("\xe2\x94\x82 \xe2\x94\x82\n");
+ }
+ }
+
+ if (bh_arr_length(dp->private_entries) > 0) {
+ bh_printf("\xe2\x94\x9c\xe2\x94\x80 Private symbols\n");
+ bh_arr_each(DocEntry, de, dp->private_entries) {
+ bh_printf("\xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80 %s\n", de->def);
+ if (de->pos.filename != NULL)
+ bh_printf("\xe2\x94\x82 \xe2\x94\x82 at %s:%d,%d\n", de->pos.filename, de->pos.line, de->pos.column);
+ else
+ bh_printf("\xe2\x94\x82 \xe2\x94\x82 compiler built-in\n");
+
+ bh_printf("\xe2\x94\x82 \xe2\x94\x82\n");
+ }
+
+ bh_printf("\n");
+ }
+ }
+ #else
+ bh_arr_each(DocPackage, dp, doc->package_docs) {
+ bh_printf("Package '%s'\n", dp->name);
+
+ if (bh_arr_length(dp->public_entries) > 0) {
+ bh_printf(" Public symbols\n");
+ bh_arr_each(DocEntry, de, dp->public_entries) {
+ bh_printf(" %s\n", de->def);
+
+ if (de->pos.filename != NULL)
+ bh_printf(" at %s:%d,%d\n", de->pos.filename, de->pos.line, de->pos.column);
+ else
+ bh_printf(" compiler built-in\n");
+
+ bh_printf(" \n");
+ }
+ }
+
+ if (bh_arr_length(dp->private_entries) > 0) {
+ bh_printf(" Private symbols\n");
+ bh_arr_each(DocEntry, de, dp->private_entries) {
+ bh_printf(" %s\n", de->def);
+ if (de->pos.filename != NULL)
+ bh_printf(" at %s:%d,%d\n", de->pos.filename, de->pos.line, de->pos.column);
+ else
+ bh_printf(" compiler built-in\n");
+
+ bh_printf(" \n");
+ }
+
+ bh_printf("\n");
+ }
+ }
+ #endif
+}
pac_node->package = p;
pac_node->token = package->alias;
- symbol_introduce(semstate.curr_package->scope, package->alias, (AstNode *) pac_node);
+ symbol_introduce(semstate.curr_package->include_scope, package->alias, (AstNode *) pac_node);
}
if (package->only != NULL) {
return;
}
- symbol_introduce(semstate.curr_package->scope, (*alias)->alias, thing);
+ symbol_introduce(semstate.curr_package->include_scope, (*alias)->alias, thing);
}
}