Skip to content

Commit

Permalink
Release 0.1.7
Browse files Browse the repository at this point in the history
Release 0.1.7
  • Loading branch information
brendanfh committed Oct 27, 2023
2 parents a7e923f + 7bbbe4c commit b1d15e3
Show file tree
Hide file tree
Showing 70 changed files with 2,895 additions and 874 deletions.
41 changes: 41 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,44 @@
Release v0.1.7
--------------
October 25th, 2023

Additions:
- Support for WASIX, a new, extended standard to WASI, popularized by Wasmer.
- Define `WASIX` in `runtime.vars` to enable it. (`-DWASIX` on the CLI)
- Adds support for networking, futexes, and TTY control in WASI.
- `switch` expressions.
- `switch` can appear at the expression level, and uses `case X => value` to
specify cases.
- `cbindgen` now supports passing functions as arguments.
- Internally uses dyncallback
- Only for OVM-wasm and Linux, for now.
- Scoped values in interfaces. `X :: ...` is allowed in an interface now.
- `#inject` works on interfaces.
- Polling to the `io.Stream` functionality.
- Used to query when data is read/write-able from a stream, for supported streams.
- `io.stream_poll`
- `misc.any_unwrap` to unwrap an `any` containing an optional.
- `json.decode_with_result`
- `json.decode_into`
- `slice.group_by`

Removals:

Changes:
- Complete overhaul of networking in the core library.
- Backwards compatiblity was not strictly maintained, but common functions did
not change, like `socket_send` and `socket_recv`.
- When debugging, `/ 0` or `% 0` will trigger an exception to debug the error.

Bugfixes:
- `alloc.atomic` package was broken when `sync` package was missing.
- `X.foo` would not work if `X` was a pointer to a union.
- Captures by pointer would break if the value was a primitive whose address wasn't
taken anywhere else.
- Symbol name reported by documentation generation was incorrect for some methods.



Release v0.1.6
-----------
24th September 2023
Expand Down
2 changes: 1 addition & 1 deletion compiler/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ fi

FLAGS="$FLAGS -DENABLE_RUN_WITH_WASMER"

if [ "$USE_DYNCALL" = "1" ]; then
if [ "$USE_DYNCALL" = "1" ] && [ "$RUNTIME_LIBRARY" = "ovmwasm" ]; then
LIBS="$LIBS ../shared/lib/linux_$ARCH/lib/libdyncall_s.a ../shared/lib/linux_$ARCH/lib/libdyncallback_s.a"
FLAGS="$FLAGS -DUSE_DYNCALL"
fi
Expand Down
15 changes: 12 additions & 3 deletions compiler/include/astnodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -881,7 +881,7 @@ typedef enum SwitchKind {
typedef struct CaseToBlock {
AstTyped *original_value;
AstBinaryOp *comparison;
AstBlock *block;
AstSwitchCase *casestmt;
} CaseToBlock;

struct AstSwitchCase {
Expand All @@ -890,16 +890,21 @@ struct AstSwitchCase {
// NOTE: All expressions that end up in this block
bh_arr(AstTyped *) values;

AstBlock *block;
union {
AstBlock *block;
AstTyped *expr;
};

AstLocal *capture;
Scope *scope; // Scope for the capture

b32 is_default: 1; // Could this be inferred by the values array being null?
b32 capture_is_by_pointer: 1;
b32 body_is_expr : 1;
};

struct AstSwitch {
AstNode_base;
AstTyped_base;

Scope *scope;
AstNode* initialization;
Expand All @@ -918,6 +923,8 @@ struct AstSwitch {
// been handled.
u8 *union_variants_handled;

b32 is_expr;

union {
struct {
// NOTE: This is a mapping from the compile time known case value
Expand Down Expand Up @@ -1213,6 +1220,8 @@ struct AstInterface {
bh_arr(InterfaceParam) params;
bh_arr(InterfaceConstraint) exprs;

Scope *scope;

b32 is_intrinsic: 1;
};

Expand Down
28 changes: 28 additions & 0 deletions compiler/src/astnodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,34 @@ TypeMatch unify_node_and_type_(AstTyped** pnode, Type* type, b32 permanent) {
}
}

if (node->kind == Ast_Kind_Switch) {
AstSwitch *switchnode = (AstSwitch *) node;
if (!switchnode->is_expr) return TYPE_MATCH_FAILED;

if (switchnode->cases == NULL) return TYPE_MATCH_YIELD;

bh_arr_each(AstSwitchCase *, pcasestmt, switchnode->cases) {
AstSwitchCase *casestmt = *pcasestmt;
if (!casestmt->body_is_expr) continue;

switch (unify_node_and_type_(&casestmt->expr, type, permanent)) {
case TYPE_MATCH_SUCCESS: break;
case TYPE_MATCH_FAILED: return TYPE_MATCH_FAILED;
case TYPE_MATCH_YIELD: return TYPE_MATCH_YIELD;
}
}

if (switchnode->default_case) {
switch (unify_node_and_type_((AstTyped **) &switchnode->default_case, type, permanent)) {
case TYPE_MATCH_SUCCESS: break;
case TYPE_MATCH_FAILED: return TYPE_MATCH_FAILED;
case TYPE_MATCH_YIELD: return TYPE_MATCH_YIELD;
}
}

if (permanent) switchnode->type = type;
return TYPE_MATCH_SUCCESS;
}

// If the destination type is an optional, and the node's type is a value of
// the same underlying type, then we can construct an optional with a value
Expand Down
73 changes: 63 additions & 10 deletions compiler/src/checker.c
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ CheckStatus check_for(AstFor* fornode) {
return Check_Success;
}

static b32 add_case_to_switch_statement(AstSwitch* switchnode, u64 case_value, AstBlock* block, OnyxFilePos pos) {
static b32 add_case_to_switch_statement(AstSwitch* switchnode, u64 case_value, AstSwitchCase* casestmt, OnyxFilePos pos) {
assert(switchnode->switch_kind == Switch_Kind_Integer || switchnode->switch_kind == Switch_Kind_Union);

switchnode->min_case = bh_min(switchnode->min_case, case_value);
Expand All @@ -373,7 +373,7 @@ static b32 add_case_to_switch_statement(AstSwitch* switchnode, u64 case_value, A
return 1;
}

bh_imap_put(&switchnode->case_map, case_value, (u64) block);
bh_imap_put(&switchnode->case_map, case_value, (u64) casestmt);
return 0;
}

Expand Down Expand Up @@ -488,7 +488,7 @@ CheckStatus check_switch(AstSwitch* switchnode) {
AstSwitchCase *sc = switchnode->cases[i];

if (sc->capture && bh_arr_length(sc->values) != 1) {
ERROR(sc->token->pos, "Expected exactly one value in switch-case when using a capture, i.e. `case X => Y { ... }`.");
ERROR(sc->token->pos, "Expected exactly one value in switch-case when using a capture, i.e. `case value: X { ... }`.");
}

if (sc->capture && switchnode->switch_kind != Switch_Kind_Union) {
Expand Down Expand Up @@ -519,7 +519,7 @@ CheckStatus check_switch(AstSwitch* switchnode) {

// NOTE: This is inclusive!!!!
fori (case_value, lower, upper + 1) {
if (add_case_to_switch_statement(switchnode, case_value, sc->block, rl->token->pos))
if (add_case_to_switch_statement(switchnode, case_value, sc, rl->token->pos))
return Check_Error;
}

Expand Down Expand Up @@ -573,7 +573,7 @@ CheckStatus check_switch(AstSwitch* switchnode) {
if (!is_valid)
ERROR_((*value)->token->pos, "Case statement expected compile time known integer. Got '%s'.", onyx_ast_node_kind_string((*value)->kind));

if (add_case_to_switch_statement(switchnode, integer_value, sc->block, sc->block->token->pos))
if (add_case_to_switch_statement(switchnode, integer_value, sc, sc->block->token->pos))
return Check_Error;

break;
Expand All @@ -592,7 +592,7 @@ CheckStatus check_switch(AstSwitch* switchnode) {
if (found) break;

CaseToBlock ctb;
ctb.block = sc->block;
ctb.casestmt = sc;
ctb.original_value = *value;
ctb.comparison = make_binary_op(context.ast_alloc, Binary_Op_Equal, switchnode->expr, *value);
ctb.comparison->token = (*value)->token;
Expand All @@ -607,13 +607,52 @@ CheckStatus check_switch(AstSwitch* switchnode) {
sc->flags |= Ast_Flag_Has_Been_Checked;

check_switch_case_block:
CHECK(block, sc->block);
if (switchnode->is_expr) {
if (!sc->body_is_expr) {
onyx_report_error(sc->token->pos, Error_Critical, "Inside a switch expression, all cases must return a value.");
ERROR(sc->token->pos, "Change the case statement to look like 'case X => expr'.");
}
} else {
if (sc->body_is_expr) {
ERROR(sc->token->pos, "This kind of case statement is only allowed in switch expressions, not switch statements.");
}
}

if (sc->body_is_expr) {
CHECK(expression, &sc->expr);
if (switchnode->type == NULL) {
switchnode->type = resolve_expression_type(sc->expr);
} else {
TYPE_CHECK(&sc->expr, switchnode->type) {
ERROR_(sc->token->pos, "Expected case expression to be of type '%s', got '%s'.",
type_get_name(switchnode->type),
type_get_name(sc->expr->type));
}
}

} else {
CHECK(block, sc->block);
}

switchnode->yield_return_index += 1;
}

if (switchnode->default_case) {
CHECK(block, switchnode->default_case);
if (switchnode->is_expr) {
AstTyped **default_case = (AstTyped **) &switchnode->default_case;
CHECK(expression, default_case);

if (switchnode->type) {
TYPE_CHECK(default_case, switchnode->type) {
ERROR_((*default_case)->token->pos, "Expected case expression to be of type '%s', got '%s'.",
type_get_name(switchnode->type),
type_get_name((*default_case)->type));
}
}

} else {
CHECK(block, switchnode->default_case);
}

} else if (switchnode->switch_kind == Switch_Kind_Union) {
// If there is no default case, and this is a union switch,
Expand Down Expand Up @@ -2403,6 +2442,10 @@ CheckStatus check_expression(AstTyped** pexpr) {
ERROR_(cl->token->pos, "Cannot pass '%b' by pointer because it is not an l-value.", cl->token->text, cl->token->length);
}

if (cl->captured_value->kind == Ast_Kind_Local) {
cl->captured_value->flags |= Ast_Flag_Address_Taken;
}

expr->type = type_make_pointer(context.ast_alloc, cl->captured_value->type);

} else {
Expand All @@ -2411,14 +2454,22 @@ CheckStatus check_expression(AstTyped** pexpr) {
break;
}

case Ast_Kind_Switch: {
AstSwitch* switch_node = (AstSwitch *) expr;
assert(switch_node->is_expr);

CHECK(switch, switch_node);
break;
}

case Ast_Kind_Switch_Case: break;
case Ast_Kind_File_Contents: break;
case Ast_Kind_Overloaded_Function: break;
case Ast_Kind_Enum_Value: break;
case Ast_Kind_Polymorphic_Proc: break;
case Ast_Kind_Package: break;
case Ast_Kind_Error: break;
case Ast_Kind_Unary_Field_Access: break;
case Ast_Kind_Switch_Case: break;
case Ast_Kind_Foreign_Block: break;
case Ast_Kind_Zero_Value: break;
case Ast_Kind_Interface: break;
Expand Down Expand Up @@ -3567,8 +3618,10 @@ CheckStatus check_constraint(AstConstraint *constraint) {
}

assert(constraint->interface->entity && constraint->interface->entity->scope);
assert(constraint->interface->scope);
assert(constraint->interface->scope->parent == constraint->interface->entity->scope);

constraint->scope = scope_create(context.ast_alloc, constraint->interface->entity->scope, constraint->token->pos);
constraint->scope = scope_create(context.ast_alloc, constraint->interface->scope, constraint->token->pos);

if (bh_arr_length(constraint->type_args) != bh_arr_length(constraint->interface->params)) {
ERROR_(constraint->token->pos, "Wrong number of arguments given to interface. Expected %d, got %d.",
Expand Down
10 changes: 10 additions & 0 deletions compiler/src/doc.c
Original file line number Diff line number Diff line change
Expand Up @@ -501,8 +501,18 @@ static void write_doc_methods(bh_buffer *buffer, Scope *method_scope) {
case Ast_Kind_Overloaded_Function: binding = ((AstOverloadedFunction *) node)->original_binding_to_node; break;
}

OnyxToken tmp_name_token;
tmp_name_token.pos = binding->token->pos;
tmp_name_token.text = method_scope->symbols[i].key;
tmp_name_token.length = strlen(tmp_name_token.text);

OnyxToken *old_token = binding->token;
binding->token = &tmp_name_token;

method_count++;
write_doc_procedure(buffer, binding, (AstNode *) node);

binding->token = old_token;
}

*((u32 *) bh_pointer_add(buffer->data, count_patch)) = method_count;
Expand Down
4 changes: 2 additions & 2 deletions 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.6"
#define VERSION "v0.1.7"


Context context;
Expand Down Expand Up @@ -934,7 +934,7 @@ static i32 onyx_compile() {
if (context.options->verbose_output > 0) {
// TODO: Replace these with bh_printf when padded formatting is added.
printf("\nStatistics:\n");
printf(" Time taken: %lf seconds\n", (double) duration / 1000);
printf(" Time taken: %lf ms\n", (double) duration);
printf(" Processed %ld lines (%f lines/second).\n", context.lexer_lines_processed, ((f32) 1000 * context.lexer_lines_processed) / (duration));
printf(" Processed %ld tokens (%f tokens/second).\n", context.lexer_tokens_processed, ((f32) 1000 * context.lexer_tokens_processed) / (duration));
printf("\n");
Expand Down

0 comments on commit b1d15e3

Please sign in to comment.