Skip to content

Commit

Permalink
Merge pull request #21 from onyx-lang/dev
Browse files Browse the repository at this point in the history
Release 0.1.5
  • Loading branch information
brendanfh authored Jul 19, 2023
2 parents 318b89f + 442ebb7 commit dae440e
Show file tree
Hide file tree
Showing 38 changed files with 549 additions and 90 deletions.
33 changes: 32 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,11 +1,42 @@
Release v0.1.5
-----------
Not released

Additions:
- Added ability to control the size of the tag type for tagged unions.
- `union #tag_type u8`
- Infrastructure to have custom sub-commands.
- Any `*.wasm` file in `$ONYX_PATH/tools` is available to run with `onyx <cmd>`
- `__futex_wait` and `__futex_wake` to platform layer.
- This allows for non-busy-waiting on mutexes and semaphores.
- Currently implemented for Onyx and JS platforms; WASI is impossible, but WASIX will come soon.
- `--skip-native` flag to `onyx pkg sync` to skip compiling native libraries.
- Ability to tag methods on structures.
- `tty_get` and `tty_set` functions in `core.os`
- Allows for controlling raw and echoed input
- Currently only for `onyx` runtime and on Linux only.
- `-Dno_entrypoint` for programs that do not have a `main` function.

Removals:
- `Wait_Notify_Available` global in `runtime` package.
- This is no longer needed as futexes are preferred instead of wait/notify.

Changes:

Bugfixes:
- Fixed bug in `json.encode` that caused arrays of structures to not be outputted correctly.
- Fixed bug in `onyx pkg` that caused `onyx pkg new` to not work as intended.



Release v0.1.4
-----------
22nd June 2023

Additions:

Removals:
- `map.get_opt`
- Deprecated `map.get_opt`.
- This is unnecessary with the new semantics of `map.get`.

Changes:
Expand Down
2 changes: 1 addition & 1 deletion build.bat
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ del *.ilk > NUL 2> NUL
del *.obj > NUL 2> NUL
del misc\icon_resource.res

cl /MT /std:c17 /TC /I compiler/include /I shared/include /D_USRDLL /D_WINDLL runtime\onyx_runtime.c /link /DLL ws2_32.lib bcrypt.lib /OUT:onyx_runtime.dll
cl /MT /std:c17 /TC /I compiler/include /I shared/include /D_USRDLL /D_WINDLL runtime\onyx_runtime.c /link /DLL ws2_32.lib bcrypt.lib Synchronization.lib /OUT:onyx_runtime.dll

del onyx_runtime.obj
del onyx_runtime.lib
Expand Down
2 changes: 2 additions & 0 deletions compiler/include/astnodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,8 @@ struct AstUnionType {
bh_arr(AstUnionVariant *) variants;
bh_arr(AstTyped *) meta_tags;

AstType *tag_backing_type;

// NOTE: Used to cache the actual type, since building
// a union type is kind of complicated and should
// only happen once.
Expand Down
4 changes: 0 additions & 4 deletions compiler/src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -600,10 +600,6 @@ void introduce_build_options(bh_allocator a) {
multi_threaded->type_node = (AstType *) &basic_type_bool;
symbol_builtin_introduce(p->scope, "Multi_Threading_Enabled", (AstNode *) multi_threaded);

AstNumLit* wait_notify_available = make_int_literal(a, context.options->use_multi_threading && context.options->runtime == Runtime_Js);
wait_notify_available->type_node = (AstType *) &basic_type_bool;
symbol_builtin_introduce(p->scope, "Wait_Notify_Available", (AstNode *) wait_notify_available);

AstNumLit* debug_mode = make_int_literal(a, context.options->debug_info_enabled);
debug_mode->type_node = (AstType *) &basic_type_bool;
symbol_builtin_introduce(p->scope, "Debug_Mode_Enabled", (AstNode *) debug_mode);
Expand Down
7 changes: 7 additions & 0 deletions compiler/src/checker.c
Original file line number Diff line number Diff line change
Expand Up @@ -3044,6 +3044,13 @@ CheckStatus check_struct_defaults(AstStructType* s_node) {
}

CheckStatus check_union(AstUnionType *u_node) {
CHECK(type, &u_node->tag_backing_type);

Type *tag_type = type_build_from_ast(context.ast_alloc, u_node->tag_backing_type);
if (!type_is_integer(tag_type)) {
ERROR_(u_node->token->pos, "Union tag types must be an integer, got '%s'.", type_get_name(tag_type));
}

if (u_node->polymorphic_argument_types) {
assert(u_node->polymorphic_arguments);

Expand Down
15 changes: 14 additions & 1 deletion compiler/src/onyx.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ extern struct bh_allocator global_heap_allocator;
#include "wasm_emit.h"
#include "doc.h"

#define VERSION "v0.1.4"
#define VERSION "v0.1.5"


Context context;
Expand Down Expand Up @@ -160,6 +160,7 @@ static CompileOptions compile_opts_parse(bh_allocator alloc, int argc, char *arg
arg_parse_start = argc;

bh_arr_push(options.files, bh_aprintf(alloc, "%s/tools/onyx-pkg.onyx", core_installation));
goto skip_parsing_arguments;
}
#ifdef ENABLE_RUN_WITH_WASMER
else if (!strcmp(argv[1], "run")) {
Expand All @@ -174,6 +175,16 @@ static CompileOptions compile_opts_parse(bh_allocator alloc, int argc, char *arg
}
#endif
else {
char *script_filename = bh_aprintf(alloc, "%s/tools/%s.wasm", core_installation, argv[1]);
if (bh_file_exists(script_filename)) {
options.action = ONYX_COMPILE_ACTION_RUN_WASM;
options.target_file = script_filename;

options.passthrough_argument_count = argc - 2;
options.passthrough_argument_data = &argv[2];
goto skip_parsing_arguments;
}

bh_printf("Unknown subcommand: '%s'\n", argv[1]);
bh_printf("Run \"onyx help\" for valid subcommands.\n");
exit(1);
Expand Down Expand Up @@ -308,6 +319,8 @@ static CompileOptions compile_opts_parse(bh_allocator alloc, int argc, char *arg
}
}

skip_parsing_arguments:

// NOTE: Always enable multi-threading for the Onyx runtime.
if (options.runtime == Runtime_Onyx) {
options.use_multi_threading = 1;
Expand Down
72 changes: 32 additions & 40 deletions compiler/src/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,23 @@ static void expect_no_stored_tags(OnyxParser *parser) {
expect_no_stored_tags_pos(parser, parser->curr->pos);
}

static b32 parse_possible_tag(OnyxParser *parser) {
b32 parsed = 0;
while (parse_possible_directive(parser, "tag") || consume_token_if_next(parser, '@')) {
parser->tag_depth += 1;
parsed = 1;

do {
AstTyped* expr = parse_expression(parser, 0);
bh_arr_push(parser->stored_tags, expr);
} while (consume_token_if_next(parser, ','));

parser->tag_depth -= 1;
}

return parsed;
}

static void flush_stored_tags(OnyxParser *parser, bh_arr(AstTyped *) *out_arr) {
//
// When tag_depth > 0, no tags will be added to the element.
Expand Down Expand Up @@ -2135,24 +2152,6 @@ static void type_create_scope(OnyxParser *parser, Scope ** scope, OnyxToken* tok
}
}

static void parse_meta_tags(OnyxParser *parser, bh_arr(AstTyped *) *out_arr) {
bh_arr(AstTyped *) meta_tags = NULL;
while (parse_possible_directive(parser, "tag") || consume_token_if_next(parser, '@')) {
if (meta_tags == NULL) bh_arr_new(global_heap_allocator, meta_tags, 1);

parser->tag_depth += 1;

do {
AstTyped* expr = parse_expression(parser, 0);
bh_arr_push(meta_tags, expr);
} while (consume_token_if_next(parser, ','));

parser->tag_depth -= 1;
}

*out_arr = meta_tags;
}

static AstStructType* parse_struct(OnyxParser* parser) {
OnyxToken *s_token = expect_token(parser, Token_Type_Keyword_Struct);

Expand Down Expand Up @@ -2244,6 +2243,8 @@ static AstStructType* parse_struct(OnyxParser* parser) {
while (!consume_token_if_next(parser, '}')) {
if (parser->hit_unexpected_token) return s_node;

parse_possible_tag(parser);

if (parse_possible_directive(parser, "persist")) {
b32 thread_local = parse_possible_directive(parser, "thread_local");

Expand All @@ -2270,7 +2271,7 @@ static AstStructType* parse_struct(OnyxParser* parser) {
}

bh_arr(AstTyped *) meta_tags=NULL;
parse_meta_tags(parser, &meta_tags);
flush_stored_tags(parser, &meta_tags);

if (parser->curr->type == '}') {
consume_token(parser);
Expand Down Expand Up @@ -2357,6 +2358,13 @@ static AstUnionType* parse_union(OnyxParser* parser) {
Scope *scope_to_restore_parser_to = parser->current_scope;
Scope *scope_symbols_in_unions_should_be_bound_to = u_node->scope;

if (parse_possible_directive(parser, "tag_type")) {
AstType *backing_type = parse_type(parser);
u_node->tag_backing_type = backing_type;
} else {
u_node->tag_backing_type = &basic_type_u32;
}

if (consume_token_if_next(parser, '(')) {
bh_arr(AstPolyStructParam) poly_params = NULL;
bh_arr_new(global_heap_allocator, poly_params, 1);
Expand Down Expand Up @@ -2399,6 +2407,8 @@ static AstUnionType* parse_union(OnyxParser* parser) {
while (!consume_token_if_next(parser, '}')) {
if (parser->hit_unexpected_token) return u_node;

parse_possible_tag(parser);

if (next_tokens_are(parser, 3, Token_Type_Symbol, ':', ':')) {
OnyxToken* binding_name = expect_token(parser, Token_Type_Symbol);
consume_token(parser);
Expand All @@ -2411,7 +2421,7 @@ static AstUnionType* parse_union(OnyxParser* parser) {
}

bh_arr(AstTyped *) meta_tags=NULL;
parse_meta_tags(parser, &meta_tags);
flush_stored_tags(parser, &meta_tags);

if (parser->curr->type == '}') {
consume_token(parser);
Expand Down Expand Up @@ -3454,6 +3464,8 @@ static void parse_top_level_statement(OnyxParser* parser) {

AstBinding* binding = NULL;

if (parse_possible_tag(parser)) return;

switch ((u16) parser->curr->type) {
case Token_Type_Keyword_Use: {
OnyxToken *use_token = expect_token(parser, Token_Type_Keyword_Use);
Expand Down Expand Up @@ -3714,15 +3726,6 @@ static void parse_top_level_statement(OnyxParser* parser) {
ENTITY_SUBMIT(library);
return;
}
else if (parse_possible_directive(parser, "tag")) {
parser->tag_depth += 1;

AstTyped *expr = parse_expression(parser, 0);
bh_arr_push(parser->stored_tags, expr);

parser->tag_depth -= 1;
return;
}
else if (parse_possible_directive(parser, "doc")) {
// This is a future feature I want to add to the language, proper docstrings.
// For now (and so I start documenting thing...), #doc can be used anywhere
Expand All @@ -3748,17 +3751,6 @@ static void parse_top_level_statement(OnyxParser* parser) {
break;
}

case '@': {
consume_token(parser);
parser->tag_depth += 1;

AstTyped *expr = parse_expression(parser, 0);
bh_arr_push(parser->stored_tags, expr);

parser->tag_depth -= 1;
return;
}

default: break;
}

Expand Down
2 changes: 2 additions & 0 deletions compiler/src/symres.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ static SymresStatus symres_union_type(AstUnionType* u_node) {
if (u_node->flags & Ast_Flag_Type_Is_Resolved) return Symres_Success;
u_node->flags |= Ast_Flag_Comptime;

SYMRES(type, &u_node->tag_backing_type);

if (u_node->meta_tags) {
bh_arr_each(AstTyped *, meta, u_node->meta_tags) {
SYMRES(expression, meta);
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/types.c
Original file line number Diff line number Diff line change
Expand Up @@ -757,7 +757,7 @@ static Type* type_build_from_ast_inner(bh_allocator alloc, AstType* type_node, b
AstEnumType* tag_enum_node = onyx_ast_node_new(alloc, sizeof(AstEnumType), Ast_Kind_Enum_Type);
tag_enum_node->token = union_->token;
tag_enum_node->name = bh_aprintf(alloc, "%s.tag_enum", union_->name);
tag_enum_node->backing_type = &basic_types[Basic_Kind_U32];
tag_enum_node->backing_type = type_build_from_ast(alloc, union_->tag_backing_type);
bh_arr_new(alloc, tag_enum_node->values, bh_arr_length(union_->variants));

void add_entities_for_node(bh_arr(Entity *) *target_arr, AstNode* node, Scope* scope, Package* package); // HACK
Expand Down Expand Up @@ -805,7 +805,7 @@ static Type* type_build_from_ast_inner(bh_allocator alloc, AstType* type_node, b
bh_arr_push(tag_enum_node->values, ev);
}

alignment = bh_max(alignment, 4);
alignment = bh_max(alignment, type_alignment_of(tag_enum_node->backing_type));
bh_align(size, alignment);

u_type->Union.alignment = alignment;
Expand Down
6 changes: 6 additions & 0 deletions core/alloc/heap.onyx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ get_freed_size :: () => {
return total;
}

#if !#defined(runtime.vars.Dont_Export_Heap_Functions) {
// heap_alloc is not exported because you can use __heap_resize(NULL, size)
#export "__heap_resize" heap_resize
#export "__heap_free" heap_free
}

#local {
use core.intrinsics.wasm {
memory_size, memory_grow,
Expand Down
2 changes: 2 additions & 0 deletions core/container/map.onyx
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ get_ptr_or_create :: (use map: &Map, key: map.Key_Type) -> &map.Value_Type {
}

#doc """
**DEPRECATED** - Use `map.get` instead.

Returns an Optional of the value at the specified key. The Optional
has a value if the key is present, otherwise the optional does not
have a value.
Expand Down
11 changes: 9 additions & 2 deletions core/conv/format.onyx
Original file line number Diff line number Diff line change
Expand Up @@ -729,9 +729,16 @@ format_any :: (output: &Format_Output, formatting: &Format, v: any) {
if info.kind == .Union {
u := cast(&Type_Info_Union) info;

tag_value := *cast(&u32, v.data);
tag_value: u64;
switch e := u.tag_enum->info()->as_enum(); e.backing_type {
case i8, u8 do tag_value = cast(u64) *(cast(&u8) v.data);
case i16, u16 do tag_value = cast(u64) *(cast(&u16) v.data);
case i32, u32 do tag_value = cast(u64) *(cast(&u32) v.data);
case i64, u64 do tag_value = cast(u64) *(cast(&u64) v.data);
case #default do assert(false, "Bad union backing type");
}

variant := array.first(u.variants, [x](x.tag_value == tag_value));
variant := array.first(u.variants, [x](x.tag_value == ~~tag_value));

if !variant {
output->write("unknown_variant");
Expand Down
1 change: 0 additions & 1 deletion core/encoding/json/encoder.onyx
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ encode :: (w: ^io.Writer, data: any) -> Encoding_Error {

a := cast(^Type_Info_Dynamic_Array) info;
arr := cast(^core.array.Untyped_Array) data.data;
data := arr.data;
count := arr.count;

for i: count {
Expand Down
6 changes: 2 additions & 4 deletions core/intrinsics/atomics.onyx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@ package core.intrinsics.atomics
}

// __atomic_wait is only valid for i32 and i64
#if runtime.Wait_Notify_Available {
__atomic_wait :: (addr: &$T, value: T, timeout: i64 = -1) -> i32 #intrinsic ---
__atomic_notify :: (addr: rawptr, maximum: i32 = 1) -> i32 #intrinsic ---
}
__atomic_wait :: (addr: &$T, value: T, timeout: i64 = -1) -> i32 #intrinsic ---
__atomic_notify :: (addr: rawptr, maximum: i32 = 1) -> i32 #intrinsic ---

__atomic_fence :: () -> void #intrinsic ---

Expand Down
Loading

0 comments on commit dae440e

Please sign in to comment.