break;
}
+ case Ast_Kind_Static_If: {
+ // At this point, the static if will be resolved. So, this
+ // only needs to add the cases from one side or another.
+
+ AstIf* static_if = (AstIf *) walker;
+ assert(static_if->flags & Ast_Flag_Static_If_Resolved);
+
+ if (static_if_resolution(static_if)) {
+ if (static_if->true_stmt) collect_switch_case_blocks(switchnode, static_if->true_stmt);
+ } else {
+ if (static_if->false_stmt) collect_switch_case_blocks(switchnode, static_if->false_stmt);
+ }
+
+ break;
+ }
+
default:
ERROR(walker->token->pos, "This statement is not allowed here.");
}
return Check_Success;
}
+ if (!type_node) goto closest_not_found;
+
char* closest = find_closest_symbol_in_node((AstNode *) type_node, field->field);
if (closest) {
ERROR_(field->token->pos, "Field '%s' does not exists on '%s'. Did you mean '%s'?", field->field, node_get_type_name(field->expr), closest);
- } else {
- ERROR_(field->token->pos, "Field '%s' does not exists on '%s'.", field->field, node_get_type_name(field->expr));
}
+
+ closest_not_found:
+ ERROR_(field->token->pos, "Field '%s' does not exists on '%s'.", field->field, node_get_type_name(field->expr));
}
// NOTE: If this member was included into the structure through a "use x: ^T" kind of statement,
CHECK(expression, &mcall->left);
if (mcall->left->type == NULL) YIELD(mcall->token->pos, "Trying to resolve type of left hand side.");
- mcall->type = mcall->left->type;
AstTyped* implicit_argument = mcall->left;
// Symbol resolution should have ensured that this is call node.
goto token_parsed;
}
- if (*tokenizer->curr == '@') {
+ /*if (*tokenizer->curr == '@') {
INCREMENT_CURR_TOKEN(tokenizer);
u32 len = 2;
while (char_is_alphanum(*(tokenizer->curr + 1)) || *(tokenizer->curr + 1) == '_') {
tk.length = len;
INCREMENT_CURR_TOKEN(tokenizer);
goto token_parsed;
- }
+ }*/
// Number literal
if (char_is_num(*tokenizer->curr)
// :LinearTokenDependent
parser->curr++;
while (parser->curr->type == Token_Type_Comment || parser->curr->type == Token_Type_Note) {
- if (parser->curr->type == Token_Type_Note) {
- AstNote* note = make_node(AstNode, Ast_Kind_Note);
- note->token = parser->curr;
- ENTITY_SUBMIT(note);
- }
+ // if (parser->curr->type == Token_Type_Note) {
+ // AstNote* note = make_node(AstNode, Ast_Kind_Note);
+ // note->token = parser->curr;
+ // ENTITY_SUBMIT(note);
+ // }
parser->curr++;
}
}
bh_arr(AstTyped *) meta_tags=NULL;
- while (parse_possible_directive(parser, "tag")) {
+ 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;
consume_tokens(parser, 2);
}
- inject->to_inject = parse_expression(parser, 0);
+ inject->to_inject = parse_top_level_expression(parser);
ENTITY_SUBMIT(inject);
return;
onyx_report_error(directive_token->pos, Error_Critical, "unknown directive '#%b'.", symbol_token->text, symbol_token->length);
return;
}
+
+ 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;
AstTyped* typed_param = lookup_param_in_arguments(func, param, args, err_msg);
if (typed_param == NULL) return;
- // CLEANUP FIXME HACK TODO GROSS
- if (typed_param->kind == Ast_Kind_Argument) {
- AstTyped* potential = ((AstArgument *) typed_param)->value;
- if (potential->kind == Ast_Kind_Polymorphic_Proc) {
- if (param->idx < (u32) bh_arr_length(func->params)) {
- AstType *param_type = func->params[param->idx].local->type_node;
- if (param_type->kind == Ast_Kind_Function_Type) {
- AstFunctionType *ft = (AstFunctionType *) param_type;
- b32 all_types = 1;
- fori (i, 0, (i32) ft->param_count) {
- if (!node_is_type((AstNode *) ft->params[i])) {
- all_types = 0;
- break;
- }
- }
-
- if (all_types) {
- typed_param = try_lookup_based_on_partial_function_type((AstFunction *) potential, ft);
- }
- }
- }
+ if (typed_param->kind != Ast_Kind_Argument) goto skip_nested_polymorph_case;
+
+ AstTyped* potential = ((AstArgument *) typed_param)->value;
+ if (potential->kind != Ast_Kind_Polymorphic_Proc) goto skip_nested_polymorph_case;
+ if (param->idx >= (u32) bh_arr_length(func->params)) goto skip_nested_polymorph_case;
+
+ AstType *param_type = func->params[param->idx].local->type_node;
+ if (param_type->kind != Ast_Kind_Function_Type) goto skip_nested_polymorph_case;
+
+ AstFunctionType *ft = (AstFunctionType *) param_type;
+ b32 all_types = 1;
+ fori (i, 0, (i32) ft->param_count) {
+ if (!node_is_type((AstNode *) ft->params[i])) {
+ all_types = 0;
+ break;
}
}
+ if (all_types)
+ typed_param = try_lookup_based_on_partial_function_type((AstFunction *) potential, ft);
+
+ skip_nested_polymorph_case:
+
actual_type = resolve_expression_type(typed_param);
if (actual_type == NULL) return;
// the alias should have passed symbol resolution. If not, force a lookup
// and yield if the alias was not ready.
if ((*fa)->expr->kind == Ast_Kind_Alias) {
- assert((*fa)->expr->entity);
- if ((*fa)->expr->entity->state < Entity_State_Check_Types) {
+ if ((*fa)->expr->entity && (*fa)->expr->entity->state < Entity_State_Check_Types) {
force_a_lookup = 1;
}
}
return Symres_Error;
}
+ //
+ // This is a small hack that makes chaining method calls
+ // work. Because check_method_call replaces the method call
+ // and marks it as completed, if there are multiple references
+ // to the same method call node, one of them will be left dangling.
+ // To remedy this, an alias node an be placed around the method call
+ // so that when check_method_call replaces it, it is replaced
+ // within the alias, and all references are updated.
+ if ((*mcall)->left->kind == Ast_Kind_Method_Call) {
+ AstAlias *left_alias = onyx_ast_node_new(context.ast_alloc, sizeof(AstAlias), Ast_Kind_Alias);
+ left_alias->token = (*mcall)->left->token;
+ left_alias->alias = (*mcall)->left;
+
+ (*mcall)->left = (AstTyped *) left_alias;
+ }
+
AstFieldAccess* implicit_field_access = make_field_access(context.ast_alloc, (*mcall)->left, NULL);
implicit_field_access->token = ((AstCall *) (*mcall)->right)->callee->token;
((AstCall *) (*mcall)->right)->callee = (AstTyped *) implicit_field_access;
return null;
}
-@Note // `arena_size` must be at least 4
+// @Note // `arena_size` must be at least 4
make :: (backing: Allocator, arena_size: u32) -> ArenaState {
assert(arena_size >= 4, "Arena size was expected to be at least 4 bytes.");
}
pool_free :: (pool: ^PoolAllocator($Elem), elem: ^Elem) {
- @TODO
+ // @TODO
// Add a check that the elem pointer is actually in the buffer??
*(cast(^rawptr) elem) = cast(rawptr) pool.first_free;
str :: #type []u8;
cstr :: #type ^u8;
-@Note
+// @Note
// Because of many implementation details, all fields of this
// struct are required to be i32's.
range :: struct {
step : i32 = 1;
}
-@Deprecated
+// @Deprecated
vararg :: #type ^struct {
data: rawptr;
count: i32;
}
-@Deprecated
+// @Deprecated
vararg_get :: #match {
(va: vararg, ret: ^$T) -> bool {
if va.count <= 0 do return false;
}
}
-@NullProcHack
+// @NullProcHack
null_proc :: () -> void #null ---
null :: cast(rawptr) 0;
x := arr.data[i];
j := i - 1;
- @ShortCircuitLogicalOps // This is written this way because '&&' does not short circuit right now.
+ // @ShortCircuitLogicalOps // This is written this way because '&&' does not short circuit right now.
while j >= 0 {
if cmp(arr.data[j], x) > 0 {
arr.data[j + 1] = arr.data[j];
-@Incomplete // This implementation is not functional at all but is something I want to get around to adding.
+// @Incomplete // This implementation is not functional at all but is something I want to get around to adding.
package core.bucket_array
fold :: #match #local {}
-@Cleanup // some way to shorten this would be nice
+// @Cleanup // some way to shorten this would be nice
#overload
fold :: macro (it: $T, init: $R, combine: $S) -> #auto where Iterable(T) {
fold :: fold
}
update :: macro (map: ^Map, key: map.Key_Type, body: Code) {
- @Hack // Weird hack because 'lookup' exists at file scope.
+ // @Hack // Weird hack because 'lookup' exists at file scope.
lookup_ :: lookup
lr := lookup_(map, key);
format_map :: (output: ^conv.Format_Output, format: ^conv.Format, x: ^Map($K, $V)) {
output->write("{\n");
for^ x.entries {
- conv.format(output, " {\"} => {\"}\n", it.key, it.value);
+ conv.format(output, " {\"p} => {\"p}\n", it.key, it.value);
}
output->write("}");
}
#local {
map :: package core.map
string :: package core.string
+ array :: package core.array
custom_formatters: Map(type_expr, #type (^Format_Output, ^Format, rawptr) -> void);
custom_parsers : Map(type_expr, #type (rawptr, str, Allocator) -> bool);
return str.{ buf.data, len };
}
-@Remove // old aliases to not break old programs
+// @Remove // old aliases to not break old programs
str_format :: format
str_format_va :: format_va
minimum_width := cast(u32) 0;
}
+#local
+flush_to_dynstr :: (dynstr: ^[..] u8, to_write: str) => {
+ array.concat(dynstr, to_write);
+ return true;
+}
+
format :: #match {}
#match format (buffer: [] u8, format: str, va: ..any) -> str {
out := format_va(*buffer, format, ~~va);
buffer.count = out.count;
}
+#match format (format: str, va: ..any) -> str {
+ buffer : [256] u8;
+ out := make([..] u8);
+ output := Format_Output.{
+ ~~buffer, 0, buffer.count,
+ flush=.{ ^out, flush_to_dynstr }
+ };
+
+ final := format_va(^output, format, ~~va);
+ array.concat(^out, final);
+
+ return out;
+}
format_va :: #match {}
#match format_va (buffer: [] u8, format: str, va: [] any, flush := Format_Flush_Callback.{}) -> str {
out := format_va(*buffer, format, va, flush);
buffer.count = out.count;
}
+#match format_va (format: [] u8, va: [] any) -> str {
+ buffer : [256] u8;
+ out := make([..] u8);
+ output := Format_Output.{
+ ~~buffer, 0, buffer.count,
+ flush=.{ ^out, flush_to_dynstr }
+ };
+
+ final := format_va(^output, format, ~~va);
+ array.concat(^out, final);
+
+ return out;
+}
#match format_va (output: ^Format_Output, format: str, va: [] any) -> str {
vararg_index := 0;
width := formatting.minimum_width;
to_output := *cast(^str) v.data;
- @Todo // escape '"' when quote_strings is enabled.
+ // @Todo // escape '"' when quote_strings is enabled.
output->write(to_output);
if to_output.count < width && !(formatting.quote_strings || formatting.single_quote_strings) {
for width - to_output.count do output->write(#char " ");
return custom_parsers[data_type](target, to_parse, string_allocator);
}
- use package runtime.info;
+ use runtime.info;
info := get_type_info(data_type);
switch data_type {
//
// For now, this will return a substring in the original to_parse.
dest := cast(^str) target;
- *dest = string.read_until(^line, #char "\"") |> string.alloc_copy(string_allocator); @BUG // This does not handle escaped strings!
+ *dest = string.read_until(^line, #char "\"") |> string.alloc_copy(string_allocator); // @BUG // This does not handle escaped strings!
return true;
}
*cast(^u32) target = ~~ str_to_i64(to_parse);
return true;
}
+
+ if info.kind == .Distinct {
+ d_info := cast(^Type_Info_Distinct) info;
+ return parse_any(target, d_info.base_type, to_parse, string_allocator);
+ }
}
}
defer i += 1;
ch := s[i];
- @Incomplete
+ // @Incomplete
switch ch {
case #char "\n" { write_byte(writer, #char "\\"); write_byte(writer, #char "n"); }
case #char "\r" { write_byte(writer, #char "\\"); write_byte(writer, #char "r"); }
case #char "\"" { write_byte(writer, #char "\\"); write_byte(writer, #char "\""); }
case #default {
- @Speed
+ // @Speed
write_byte(writer, ch);
}
}
Dying;
Dead;
}
+
+ read_complete :: (use this: ^Client) {
+ recv_ready_event_present = false;
+ }
}
client_allocator: Allocator;
clients: [] ^Client;
conn_event := new(TCP_Event.Connection, allocator=server.event_allocator);
conn_event.address = ^client.address;
conn_event.client = client;
- server.events << .{ .Connection, conn_event }; @Threading // This operation should be protected by a mutex?
+ server.events << .{ .Connection, conn_event }; // @Threading // This operation should be protected by a mutex?
}
}
data_event.client = it;
data_event.address = ^it.address;
data_event.contents = memory.copy_slice(msg_buffer[0 .. bytes_read], allocator=server.event_allocator);
- server.events << .{ .Data, data_event }; @Threading // See comment above.
+ server.events << .{ .Data, data_event }; // @Threading // See comment above.
} elseif !it.recv_ready_event_present {
it.recv_ready_event_present = true;
ready_event := new(TCP_Event.Ready, allocator=server.event_allocator);
ready_event.client = it;
ready_event.address = ^it.address;
- server.events << .{ .Ready, ready_event }; @Threading // See comment above.
+ server.events << .{ .Ready, ready_event }; // @Threading // See comment above.
}
}
disconnect_event := new(TCP_Event.Disconnection, allocator=server.event_allocator);
disconnect_event.client = it;
disconnect_event.address = ^it.address;
- server.events << .{ .Disconnection, disconnect_event }; @Threading // See comment above.
+ server.events << .{ .Disconnection, disconnect_event }; // @Threading // See comment above.
}
}
for clients {
if it == null do continue;
- if it.state == .Alive {
+ if it.state == .Alive && !it.recv_ready_event_present {
active_clients[active_clients.count] = it;
active_clients.count += 1;
}
if t1.is_variadic != t2.is_variadic do return false;
while i := 0; i < t1.parameter_types.count {
- @Robustness // This does not handle nested procedure types
+ // @Robustness // This does not handle nested procedure types
if t1.parameter_types[i] != t2.parameter_types[i] do return false;
}
Type_Info_Pointer :: struct {
use base : Type_Info;
- @Rename
+ // @Rename
to: type_expr;
}
Type_Info_Array :: struct {
use base : Type_Info;
- @Rename
+ // @Rename
of: type_expr;
count: u32;
}
Type_Info_Slice :: struct {
use base : Type_Info;
- @Rename
+ // @Rename
of: type_expr;
}
Type_Info_Dynamic_Array :: struct {
use base : Type_Info;
- @Rename
+ // @Rename
of: type_expr;
}
Type_Info_Variadic_Argument :: struct {
use base : Type_Info;
- @Rename
+ // @Rename
of: type_expr;
}
return str.{ data, len1 + len2 };
}
-@Cleanup // Don't love that the allocator is necessary here,
+// @Cleanup // Don't love that the allocator is necessary here,
// but it is impossible to specify a default value for the
// allocator while having a variadic number of strings. This
// is only due to the languages constraints however. This
}
-@TODO
+// @TODO
// Check this for edge cases and other bugs. I'm not confident
// it will work perfectly yet. - brendanfh 2020/12/21
compare :: (str1: str, str2: str) -> i32 {
if m.owner == context.thread_id do return;
#if runtime.Wait_Notify_Available {
- @ThreadingCleanup // You cannot wait on the main thread in
+ // @ThreadingCleanup // You cannot wait on the main thread in
// a web browser, for kind of obvious reasons. However, this
// makes waiting for a mutex expensive because the only option
// is to do a spin-lock. Ugh.
scoped_mutex(^s.mutex);
s.counter += count;
- @Bug // This is susceptible to starvation. Semaphores should have a queue
+ // @Bug // This is susceptible to starvation. Semaphores should have a queue
// or something like that.
#if runtime.Wait_Notify_Available {
__atomic_notify(^s.counter, maximum = count);
}
}
- @TODO // provide a better error code.
+ // @TODO // provide a better error code.
return file, .NotFound;
}
. ../settings.sh
-$CC -shared -fpic -w \
+$CC -shared -fpic -w -O2 \
-o ../bin/onyx_runtime.so \
-I ../shared/include -I ../compiler/include \
./onyx_runtime.c \
}
}
- @TODO // Validation for these fields.
+ // @TODO // Validation for these fields.
r := io.reader_make(^stdio_stream);
read_field("Package name: ", ^config.metadata.name);
read_field("Package description: ", ^config.metadata.description);
}
#tag Command.{ "update", "Update dependencies to newest compatible versions.", "" }
-@Feature // Add "locked" dependencies that will never update?
+// @Feature // Add "locked" dependencies that will never update?
run_update_command :: (args: [] cstr) {
printf("Updating dependencies to newest compatible versions.\n");
for^ config.dependencies.dependencies.entries {
#tag Command.{ "publish", "Bump version number and create a publishable version of the package", "" }
run_publish_command :: (args: [] cstr) {
- @TODO // Better error handling and reporting, as this is a delicate process.
+ // @TODO // Better error handling and reporting, as this is a delicate process.
if !os.dir_exists(".git") {
printf("It does not look like you are in a Git repository. In order to publish packages\n");
// The executable to use when compiling
onyx_cmd: str;
at_least_one_test_failed := false;
- compile_only := false; @Bug // why is this necessary? why is settings.compile_only false when in the thread code?
+ compile_only := false; // @Bug // why is this necessary? why is settings.compile_only false when in the thread code?
}
exec_context := init(Execution_Context);
exec_context.compile_only = settings.compile_only;
main :: (args: [] cstr) {
- @CoreLibraries // The commented out cases can be re-enabled when f64_to_str is better.
+ // @CoreLibraries // The commented out cases can be re-enabled when f64_to_str is better.
// Right now there is an integer overflow because it converts the float to an i64.
strings := str.[
/* these should parse fully */