From: Brendan Hansen Date: Thu, 26 Aug 2021 14:50:11 +0000 (-0500) Subject: code cleanup in cloner and checker. proper cycle detection again X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=78c61e4c2d3c96c37ad7e874abea61b66717e222;p=onyx.git code cleanup in cloner and checker. proper cycle detection again --- diff --git a/bin/onyx b/bin/onyx index 4c0e4e12..daf84b19 100755 Binary files a/bin/onyx and b/bin/onyx differ diff --git a/core/alloc/heap.onyx b/core/alloc/heap.onyx index e76ad66b..33722d0b 100644 --- a/core/alloc/heap.onyx +++ b/core/alloc/heap.onyx @@ -232,3 +232,5 @@ init :: () { heap_allocator.data = ^heap_state; heap_allocator.func = heap_alloc_proc; } + +get_watermark :: () => cast(u32) heap_state.next_alloc; \ No newline at end of file diff --git a/core/container/array.onyx b/core/container/array.onyx index 16eb82ed..88e5180d 100644 --- a/core/container/array.onyx +++ b/core/container/array.onyx @@ -389,15 +389,19 @@ first :: #match { } count_where :: #match { - (arr: ^[..] $T, predicate: (T) -> bool) -> u32 { + (arr: ^[..] $T, predicate: $Pred) -> u32 { + return count_where((#type [] T).{ arr.data, arr.count }, predicate); + }, + + (arr: [] $T, predicate: (T) -> bool) -> u32 { count: u32 = 0; - for ^it: *arr do if predicate(*it) do count += 1; + for ^it: arr do if predicate(*it) do count += 1; return count; }, - (arr: ^[..] $T, predicate: (^T) -> bool) -> u32 { + (arr: [] $T, predicate: (^T) -> bool) -> u32 { count: u32 = 0; - for ^it: *arr do if predicate(it) do count += 1; + for ^it: arr do if predicate(it) do count += 1; return count; }, } diff --git a/core/container/iter.onyx b/core/container/iter.onyx index 8f4c8e69..97217cb2 100644 --- a/core/container/iter.onyx +++ b/core/container/iter.onyx @@ -67,6 +67,12 @@ map :: (it: Iterator($T), transform: (T) -> $R) -> Iterator(R) { }; } +take_one :: (it: Iterator($T)) -> (T, bool) { + ret, cont := it.next(it.data); + if !cont do it.close(it.data); + return ret, cont; +} + take :: (it: Iterator($T), count: u32) -> Iterator(T) { TakeIterator :: struct (T: type_expr) { iterator: Iterator(T); diff --git a/core/io/reader.onyx b/core/io/reader.onyx index bfacd02f..bbb13f43 100644 --- a/core/io/reader.onyx +++ b/core/io/reader.onyx @@ -22,6 +22,10 @@ reader_from_string :: (s: str) -> (Reader, ^StringStream) { return Reader.{ stream_ptr }, stream_ptr; } +reader_empty :: (use reader: ^Reader) -> bool { + return stream_end_of_file(stream); +} + read_byte :: (use reader: ^Reader) -> u8 { err, byte := stream_read_byte(stream); return byte; @@ -40,6 +44,60 @@ read_bytes :: #match { } } +read_i32 :: (use reader: ^Reader) -> i32 { + n: i32 = 0; + + skip_whitespace(reader); + + is_negative := false; + err, curr := stream_peek_byte(stream); + if curr == #char "-" { + is_negative = true; + err, curr = stream_read_byte(stream); + err, curr = stream_peek_byte(stream); + } + + while curr >= #char "0" && curr <= #char "9" { + err, curr = stream_read_byte(stream); + + n *= 10; + n += cast(u32) (curr - #char "0"); + + err, curr = stream_peek_byte(stream); + if err == Error.EOF do break; + } + + if is_negative do n = -n; + return n; +} + +read_i64 :: (use reader: ^Reader) -> i64 { + n: i64 = 0; + + skip_whitespace(reader); + + is_negative := false; + err, curr := stream_peek_byte(stream); + if curr == #char "-" { + is_negative = true; + err, curr = stream_read_byte(stream); + err, curr = stream_peek_byte(stream); + } + + while curr >= #char "0" && curr <= #char "9" { + err, curr = stream_read_byte(stream); + + n *= 10; + n += cast(u64) (curr - #char "0"); + + err, curr = stream_peek_byte(stream); + if err == Error.EOF do break; + } + + if is_negative do n = -n; + return n; +} + read_u32 :: (use reader: ^Reader) -> u32 { n: u32 = 0; diff --git a/core/math.onyx b/core/math.onyx index 2886c730..5396f70d 100644 --- a/core/math.onyx +++ b/core/math.onyx @@ -197,6 +197,22 @@ pow :: #match { } } +power_mod :: (base: u32, exp: u32, mod: u32) -> u32 { + t: u64 = 1; + e: u64 = ~~exp; + b: u64 = ~~base; + m: u64 = ~~mod; + + while e > 0 { + if e % 2 != 0 do t = (t * b) % m; + + b = (b * b) % m; + e /= 2; + } + + return ~~(t % m); +} + ln :: (a: f32) -> f32 { // FIX: This is probably not the most numerically stable solution. if a < 1 { diff --git a/core/string.onyx b/core/string.onyx index 4cafb683..b5d011bc 100644 --- a/core/string.onyx +++ b/core/string.onyx @@ -169,6 +169,11 @@ ends_with :: (s: str, suffix: str) -> bool { return true; } +strip_whitespace :: #match { + (s: ^str) { strip_leading_whitespace(s); strip_trailing_whitespace(s); }, + (s: str) { strip_leading_whitespace(s); strip_trailing_whitespace(s); }, +} + strip_leading_whitespace :: #match { (s: ^str) { while true do switch s.data[0] { diff --git a/core/string/reader.onyx b/core/string/reader.onyx index 0cea068a..503c9d60 100644 --- a/core/string/reader.onyx +++ b/core/string/reader.onyx @@ -71,6 +71,8 @@ read_byte :: (use reader: ^String_Reader) -> u8 { return data[0]; } +peek_byte :: (use reader: ^String_Reader) -> u8 do return data[0]; + read_bytes :: (use reader: ^String_Reader, byte_count := 1) -> str { bc := byte_count; if count < bc do bc = count; @@ -131,13 +133,14 @@ read_until :: (use reader: ^String_Reader, skip: u32, uptos: ..u8) -> str { } // Reads a continuous string of alphabetic chars along with underscores '_' -read_word :: (use reader: ^String_Reader) -> str { +read_word :: (use reader: ^String_Reader, numeric_allowed := false) -> str { if count == 0 do return str.{ null, 0 }; out := str.{ data, 0 }; for ch: *(cast(^str) reader) { if (ch >= #char "a" && ch <= #char "z") || (ch >= #char "A" && ch <= #char "Z") + || (numeric_allowed && (ch >= #char "0" && ch <= #char "9")) || ch == #char "_" { out.count += 1; } diff --git a/docs/bugs b/docs/bugs index d3d19cde..d78b9824 100644 --- a/docs/bugs +++ b/docs/bugs @@ -1,5 +1,13 @@ List of known bugs: +[ ] macros are not allowed at the expression level. This is not necessarily a bug, but does + bring many complications to the table about how resolve this. + +[ ] recursive quick-procedures / procedures that use #auto have trouble if the first lexical + return statement is a recursive call. + +[X] There is not proper cycle detection in the compiler. Infinite should not be possible. + [ ] Compound assignment operators such as += evaluate the location of their left-value twice. Not only is this bad for efficiency, if the value requires calling a function, that function will be called twice instead of once. This is a simple code generation fix, diff --git a/src/onyx.c b/src/onyx.c index ec2d87fa..75d7797b 100644 --- a/src/onyx.c +++ b/src/onyx.c @@ -403,6 +403,23 @@ static void output_dummy_progress_bar() { } #endif +static void dump_cycles() { + context.cycle_detected = 1; + Entity* ent; + + onyx_report_error((OnyxFilePos) { 0 }, "Cycle detected. Dumping all stuck processing units."); + + while (1) { + ent = entity_heap_top(&context.entities); + entity_heap_remove_top(&context.entities); + if (ent->state < Entity_State_Code_Gen) process_entity(ent); + + if (bh_arr_length(context.entities.entities) == 0) { + break; + } + } +} + static i32 onyx_compile() { u64 start_time = bh_time_curr(); @@ -440,12 +457,20 @@ static i32 onyx_compile() { // before the "key" node that will unblock the progress. This means a more sophisticated // cycle detection algorithm must be used. // - static Entity* first_no_change = NULL; + static Entity* watermarked_node = NULL; if (!changed) { - if (!first_no_change) first_no_change = ent; - else if (first_no_change == ent) context.cycle_detected = 1; + if (!watermarked_node) { + watermarked_node = ent; + } + else if (watermarked_node == ent) { + entity_heap_insert_existing(&context.entities, ent); + dump_cycles(); + } + else if (watermarked_node->macro_attempts < ent->macro_attempts) { + watermarked_node = ent; + } } else { - first_no_change = NULL; + watermarked_node = NULL; } if (onyx_has_errors()) return ONYX_COMPILER_PROGRESS_ERROR; diff --git a/src/onyxchecker.c b/src/onyxchecker.c index 945d25b9..e4c99dd3 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -11,6 +11,24 @@ if (cs > Check_Errors_Start) return cs; \ } while (0) +#define YIELD(loc, msg) do { \ + if (context.cycle_detected) { \ + onyx_report_error(loc, msg); \ + return Check_Error; \ + } else { \ + return Check_Yield_Macro; \ + } \ + } while (0) + +#define YIELD_(loc, msg, ...) do { \ + if (context.cycle_detected) { \ + onyx_report_error(loc, msg, __VA_ARGS__); \ + return Check_Error; \ + } else { \ + return Check_Yield_Macro; \ + } \ + } while (0) + typedef enum CheckStatus { Check_Success, // The node was successfully checked with out errors Check_Complete, // The node is done processing @@ -116,7 +134,8 @@ CheckStatus check_return(AstReturn* retnode) { if (*expected_return_type == &type_auto_return) { resolve_expression_type(retnode->expr); - if (retnode->expr->type == NULL) return Check_Yield_Macro; + if (retnode->expr->type == NULL) + YIELD(retnode->token->pos, "Trying to determine automatic return type."); *expected_return_type = retnode->expr->type; return Check_Success; @@ -152,7 +171,7 @@ CheckStatus check_if(AstIfWhile* ifnode) { if (ifnode->kind == Ast_Kind_Static_If) { if ((ifnode->flags & Ast_Flag_Static_If_Resolved) == 0) { - return Check_Yield_Macro; + YIELD(ifnode->token->pos, "Waiting for static if to be resolved."); } if (static_if_resolution(ifnode)) { @@ -442,7 +461,7 @@ static CheckStatus check_resolve_callee(AstCall* call, AstTyped** effective_call return Check_Error; } else { - return Check_Yield_Macro; + YIELD(call->token->pos, "Waiting for overloaded function option to pass type-checking."); } } @@ -459,16 +478,20 @@ static CheckStatus check_resolve_callee(AstCall* call, AstTyped** effective_call call->callee = callee; AstTyped* new_callee = (AstTyped *) macro_resolve_header((AstMacro *) callee, &call->args, call->token); - if (new_callee == (AstTyped *) &node_that_signals_a_yield) return Check_Yield_Macro; if (new_callee == NULL) return Check_Error; + if (new_callee == (AstTyped *) &node_that_signals_a_yield) { + YIELD(call->token->pos, "Waiting for macro header to pass type-checking."); + } arguments_remove_baked(&call->args); callee = new_callee; } else if (callee->kind == Ast_Kind_Polymorphic_Proc) { AstTyped* new_callee = (AstTyped *) polymorphic_proc_lookup((AstPolyProc *) callee, PPLM_By_Arguments, &call->args, call->token); - if (new_callee == (AstTyped *) &node_that_signals_a_yield) return Check_Yield_Macro; if (new_callee == NULL) return Check_Error; + if (new_callee == (AstTyped *) &node_that_signals_a_yield) { + YIELD(call->token->pos, "Waiting for polymorphic procedure header to pass type-checking."); + } arguments_remove_baked(&call->args); callee = new_callee; @@ -478,7 +501,9 @@ static CheckStatus check_resolve_callee(AstCall* call, AstTyped** effective_call // NOTE: Build callee's type fill_in_type((AstTyped *) callee); - if (callee->type == NULL) return Check_Yield_Macro; + if (callee->type == NULL) { + YIELD(call->token->pos, "Trying to resolve function type for callee."); + } if (callee->type->kind != Type_Kind_Function) { onyx_report_error(call->token->pos, @@ -608,7 +633,9 @@ CheckStatus check_call(AstCall** pcall) { call->va_kind = VA_Kind_Not_VA; call->type = callee->type->Function.return_type; - if (call->type == &type_auto_return) return Check_Yield_Macro; + if (call->type == &type_auto_return) { + YIELD(call->token->pos, "Waiting for auto-return type to be solved."); + } Type **formal_params = callee->type->Function.params; @@ -766,7 +793,7 @@ CheckStatus check_binaryop_assignment(AstBinaryOp* binop) { return Check_Error; } else { - return Check_Yield_Macro; + YIELD(binop->token->pos, "Trying to resolve try of right hand side."); } } @@ -824,7 +851,7 @@ CheckStatus check_binaryop_assignment(AstBinaryOp* binop) { if (binop->right->type == NULL) { if (binop->right->entity != NULL && binop->right->entity->state <= Entity_State_Check_Types) { - return Check_Yield_Macro; + YIELD(binop->token->pos, "Trying to resolve type of right hand side."); } } @@ -1026,7 +1053,7 @@ CheckStatus check_binaryop(AstBinaryOp** pbinop) { AstCall *implicit_call = binaryop_try_operator_overload(binop); if (implicit_call == (AstCall *) &node_that_signals_a_yield) - return Check_Yield_Macro; + YIELD(binop->token->pos, "Trying to resolve operator overload."); if (implicit_call != NULL) { // NOTE: Not a binary op @@ -1125,7 +1152,8 @@ CheckStatus check_unaryop(AstUnaryOp** punop) { if (unaryop->operation == Unary_Op_Cast) { char* err; - if (unaryop->type == NULL) return Check_Yield_Macro; + if (unaryop->type == NULL) + YIELD(unaryop->token->pos, "Trying to resolve destination type for cast."); if (!cast_is_legal(unaryop->expr->type, unaryop->type, &err)) { onyx_report_error(unaryop->token->pos, "Cast Error: %s", err); @@ -1176,7 +1204,8 @@ CheckStatus check_struct_literal(AstStructLiteral* sl) { } fill_in_type((AstTyped *) sl); - if (sl->type == NULL) return Check_Yield_Macro; + if (sl->type == NULL) + YIELD(sl->token->pos, "Trying to resolve type of struct literal."); } if (!type_is_structlike_strict(sl->type)) { @@ -1222,21 +1251,21 @@ CheckStatus check_struct_literal(AstStructLiteral* sl) { sl->flags |= Ast_Flag_Comptime; fori (i, 0, mem_count) { + // NOTE: Not checking the return on this function because + // this for loop is bounded by the number of members in the + // type. + type_lookup_member_by_idx(sl->type, i, &smem); + Type* formal = smem.type; + CHECK(expression, actual); // HACK HACK HACK if ((*actual)->type == NULL && (*actual)->entity != NULL && (*actual)->entity->state <= Entity_State_Check_Types) { - return Check_Yield_Macro; + YIELD_((*actual)->token->pos, "Trying to resolve type of expression for member '%s'.", smem.name); } - // NOTE: Not checking the return on this function because - // this for loop is bounded by the number of members in the - // type. - type_lookup_member_by_idx(sl->type, i, &smem); - Type* formal = smem.type; - if (!type_check_or_auto_cast(actual, formal)) { onyx_report_error(sl->token->pos, "Mismatched types for %d%s member named '%s', expected '%s', got '%s'.", @@ -1265,7 +1294,8 @@ CheckStatus check_array_literal(AstArrayLiteral* al) { } fill_in_type((AstTyped *) al); - if (al->type == NULL) return Check_Yield_Macro; + if (al->type == NULL) + YIELD(al->token->pos, "Trying to resolve type of array literal."); al->type = type_make_array(context.ast_alloc, al->type, bh_arr_length(al->values)); if (al->type == NULL || al->type->kind != Type_Kind_Array) { @@ -1292,7 +1322,7 @@ CheckStatus check_array_literal(AstArrayLiteral* al) { if ((*expr)->type == NULL && (*expr)->entity != NULL && (*expr)->entity->state <= Entity_State_Check_Types) { - return Check_Yield_Macro; + YIELD_(al->token->pos, "Trying to resolve type of %d%s element of array literal.", expr - al->values, bh_num_suffix(expr - al->values)); } al->flags &= ((*expr)->flags & Ast_Flag_Comptime) | (al->flags &~ Ast_Flag_Comptime); @@ -1377,7 +1407,7 @@ CheckStatus check_if_expression(AstIfExpression* if_expr) { CheckStatus check_address_of(AstAddressOf* aof) { CHECK(expression, &aof->expr); if (aof->expr->type == NULL) { - return Check_Yield_Macro; + YIELD(aof->token->pos, "Trying to resolve type of expression to take a reference."); } if ((aof->expr->kind != Ast_Kind_Subscript @@ -1428,7 +1458,7 @@ CheckStatus check_subscript(AstSubscript** psub) { AstCall *implicit_call = binaryop_try_operator_overload(binop); if (implicit_call == (AstCall *) &node_that_signals_a_yield) - return Check_Yield_Macro; + YIELD(sub->token->pos, "Trying to resolve operator overload."); if (implicit_call != NULL) { // NOTE: Not an array access @@ -1510,7 +1540,7 @@ CheckStatus check_field_access(AstFieldAccess** pfield) { CHECK(expression, &field->expr); if (field->expr->type == NULL) { // onyx_report_error(field->token->pos, "Unable to deduce type of expression for accessing field."); - return Check_Yield_Macro; + YIELD(field->token->pos, "Trying to resolve type of source expression."); } if (!type_is_structlike(field->expr->type)) { @@ -1562,7 +1592,7 @@ CheckStatus check_field_access(AstFieldAccess** pfield) { CheckStatus check_method_call(AstBinaryOp** mcall) { CHECK(expression, &(*mcall)->left); if ((*mcall)->left->type == NULL) { - return Check_Yield_Macro; + YIELD((*mcall)->token->pos, "Trying to resolve type of left hand side."); } AstTyped* implicit_argument = (*mcall)->left; @@ -1598,7 +1628,8 @@ CheckStatus check_size_of(AstSizeOf* so) { CHECK(type, so->so_ast_type); so->so_type = type_build_from_ast(context.ast_alloc, so->so_ast_type); - if (so->so_type == NULL) return Check_Yield_Macro; + if (so->so_type == NULL) + YIELD(so->token->pos, "Trying to resolve type to take the size of."); so->size = type_size_of(so->so_type); @@ -1610,7 +1641,8 @@ CheckStatus check_align_of(AstAlignOf* ao) { CHECK(type, ao->ao_ast_type); ao->ao_type = type_build_from_ast(context.ast_alloc, ao->ao_ast_type); - if (ao->ao_type == NULL) return Check_Yield_Macro; + if (ao->ao_type == NULL) + YIELD(ao->token->pos, "Trying to resolve type to take the alignment of."); ao->alignment = type_alignment_of(ao->ao_type); @@ -1628,7 +1660,7 @@ CheckStatus check_expression(AstTyped** pexpr) { } if (type_build_from_ast(context.ast_alloc, (AstType*) expr) == NULL) { - return Check_Yield_Macro; + YIELD(expr->token->pos, "Trying to construct type."); } expr->type = &basic_types[Basic_Kind_Type_Index]; @@ -1714,7 +1746,8 @@ CheckStatus check_expression(AstTyped** pexpr) { // break; // } // } - if (expr->type == NULL) return Check_Yield_Macro; + if (expr->type == NULL) + YIELD(expr->token->pos, "Waiting for function type to be resolved."); expr->flags |= Ast_Flag_Function_Used; break; @@ -1804,7 +1837,8 @@ CheckStatus check_insert_directive(AstDirectiveInsert** pinsert) { return Check_Error; } - return Check_Yield_Macro; + // Bad wording for the message. + YIELD(insert->token->pos, "Waiting for resolution to code expression type."); } Type* code_type = type_build_from_ast(context.ast_alloc, builtin_code_type); @@ -1874,8 +1908,8 @@ CheckStatus check_statement(AstNode** pstmt) { onyx_report_error(stmt->token->pos, "Local's type is not a type."); return Check_Error; } - - return Check_Yield_Macro; + + YIELD(typed_stmt->token->pos, "Waiting for local variable's type."); } return Check_Success; } @@ -1926,7 +1960,8 @@ CheckStatus check_block(AstBlock* block) { CheckStatus check_function(AstFunction* func) { if (func->flags & Ast_Flag_Already_Checked) return Check_Success; - if (func->entity_header && func->entity_header->state < Entity_State_Code_Gen) return Check_Yield_Macro; + if (func->entity_header && func->entity_header->state < Entity_State_Code_Gen) + YIELD(func->token->pos, "Waiting for procedure header to pass type-checking"); expected_return_type = &func->type->Function.return_type; if (func->body) { @@ -1978,11 +2013,12 @@ CheckStatus check_overloaded_function(AstOverloadedFunction* func) { bh_imap_free(&all_overloads); if (done) return Check_Success; - else return Check_Yield_Macro; + else YIELD(func->token->pos, "Waiting for all options to pass type-checking."); } CheckStatus check_struct(AstStructType* s_node) { - if (s_node->entity_defaults && s_node->entity_defaults->state < Entity_State_Check_Types) return Check_Yield_Macro; + if (s_node->entity_defaults && s_node->entity_defaults->state < Entity_State_Check_Types) + YIELD(s_node->token->pos, "Waiting for struct member definitions to pass symbol resolution."); bh_arr_each(AstStructMember *, smem, s_node->members) { if ((*smem)->type_node != NULL) { @@ -1993,7 +2029,8 @@ CheckStatus check_struct(AstStructType* s_node) { CHECK(expression, &(*smem)->initial_value); fill_in_type((*smem)->initial_value); - if ((*smem)->initial_value->type == NULL) return Check_Yield_Macro; + if ((*smem)->initial_value->type == NULL) + YIELD((*smem)->initial_value->token->pos, "Trying to resolve type for initial value for member."); resolve_expression_type((*smem)->initial_value); if ((*smem)->type == NULL) (*smem)->type = (*smem)->initial_value->type; @@ -2007,7 +2044,8 @@ CheckStatus check_struct(AstStructType* s_node) { // NOTE: fills in the stcache type_build_from_ast(context.ast_alloc, (AstType *) s_node); - if (s_node->stcache == NULL || !s_node->stcache_is_valid) return Check_Yield_Macro; + if (s_node->stcache == NULL || !s_node->stcache_is_valid) + YIELD(s_node->token->pos, "Waiting for type to be constructed."); bh_arr_each(StructMember *, smem, s_node->stcache->Struct.memarr) { if ((*smem)->type->kind == Type_Kind_Compound) { @@ -2020,7 +2058,8 @@ CheckStatus check_struct(AstStructType* s_node) { } CheckStatus check_struct_defaults(AstStructType* s_node) { - if (s_node->entity_type && s_node->entity_type->state < Entity_State_Code_Gen) return Check_Yield_Macro; + if (s_node->entity_type && s_node->entity_type->state < Entity_State_Code_Gen) + YIELD(s_node->token->pos, "Waiting for struct type to be constructed before checking defaulted members."); bh_arr_each(StructMember *, smem, s_node->stcache->Struct.memarr) { if ((*smem)->initial_value && *(*smem)->initial_value) { @@ -2042,7 +2081,8 @@ CheckStatus check_struct_defaults(AstStructType* s_node) { } CheckStatus check_function_header(AstFunction* func) { - if (func->entity_body && func->entity_body->state < Entity_State_Check_Types) return Check_Yield_Macro; + if (func->entity_body && func->entity_body->state < Entity_State_Check_Types) + YIELD(func->token->pos, "Waiting for function header to complete symbol resolution"); b32 expect_default_param = 0; b32 has_had_varargs = 0; @@ -2105,7 +2145,7 @@ CheckStatus check_function_header(AstFunction* func) { // "Unable to resolve type for parameter, '%b'", // local->token->text, // local->token->length); - return Check_Yield_Macro; + YIELD(local->token->pos, "Waiting for parameter type to be known."); } if (local->type->kind == Type_Kind_Compound) { @@ -2139,7 +2179,7 @@ CheckStatus check_function_header(AstFunction* func) { if (func->return_type != NULL) CHECK(type, func->return_type); func->type = type_build_function_type(context.ast_alloc, func); - if (func->type == NULL) return Check_Yield_Macro; + if (func->type == NULL) YIELD(func->token->pos, "Waiting for function type to be constructed"); return Check_Success; } @@ -2147,7 +2187,7 @@ CheckStatus check_function_header(AstFunction* func) { CheckStatus check_memres_type(AstMemRes* memres) { CHECK(type, memres->type_node); fill_in_type((AstTyped *) memres); - if (memres->type_node && !memres->type) return Check_Yield_Macro; + if (memres->type_node && !memres->type) YIELD(memres->token->pos, "Waiting for global type to be constructed."); return Check_Success; } @@ -2173,7 +2213,7 @@ CheckStatus check_memres(AstMemRes* memres) { } else { if (memres->initial_value->type == NULL && memres->initial_value->entity != NULL && memres->initial_value->entity->state <= Entity_State_Check_Types) { - return Check_Yield_Macro; + YIELD(memres->token->pos, "Waiting for global type to be constructed."); } memres->type = memres->initial_value->type; } @@ -2208,7 +2248,7 @@ CheckStatus check_type(AstType* type) { resolve_expression_type(type_of->expr); if (type_of->expr->type == NULL) { - return Check_Yield_Macro; + YIELD(type_of->token->pos, "Trying to check type for type-of expression."); } type_of->resolved_type = type_of->expr->type; @@ -2288,7 +2328,8 @@ CheckStatus check_static_if(AstIf* static_if) { CheckStatus check_process_directive(AstNode* directive) { if (directive->kind == Ast_Kind_Directive_Export) { AstTyped* export = ((AstDirectiveExport *) directive)->export; - if (export->entity && export->entity->state <= Entity_State_Check_Types) return Check_Yield_Macro; + if (export->entity && export->entity->state <= Entity_State_Check_Types) + YIELD(directive->token->pos, "Waiting for export type to be known."); } return Check_Success; diff --git a/src/onyxclone.c b/src/onyxclone.c index dbc36773..425a2dca 100644 --- a/src/onyxclone.c +++ b/src/onyxclone.c @@ -122,6 +122,8 @@ AstNode* ast_clone_list(bh_allocator a, void* n) { return root; } +#define C(nt, mname) ((nt *) nn)->mname = (void *) ast_clone(a, ((nt *) node)->mname); + // NOTE: Using void* to avoid a lot of unnecessary casting AstNode* ast_clone(bh_allocator a, void* n) { AstNode* node = (AstNode *) n; @@ -142,18 +144,18 @@ AstNode* ast_clone(bh_allocator a, void* n) { case Ast_Kind_Binary_Op: case Ast_Kind_Pipe: case Ast_Kind_Method_Call: - ((AstBinaryOp *) nn)->left = (AstTyped *) ast_clone(a, ((AstBinaryOp *) node)->left); - ((AstBinaryOp *) nn)->right = (AstTyped *) ast_clone(a, ((AstBinaryOp *) node)->right); + C(AstBinaryOp, left); + C(AstBinaryOp, right); break; case Ast_Kind_Unary_Op: - ((AstUnaryOp *) nn)->expr = (AstTyped *) ast_clone(a, ((AstUnaryOp *) node)->expr); - ((AstUnaryOp *) nn)->type_node = (AstType *) ast_clone(a, ((AstUnaryOp *) node)->type_node); + C(AstUnaryOp, expr); + C(AstUnaryOp, type_node); break; case Ast_Kind_Param: case Ast_Kind_Local: - ((AstLocal *) nn)->type_node = (AstType *) ast_clone(a, ((AstLocal *) node)->type_node); + C(AstLocal, type_node); break; case Ast_Kind_Call: @@ -161,33 +163,33 @@ AstNode* ast_clone(bh_allocator a, void* n) { break; case Ast_Kind_Argument: - ((AstArgument *) nn)->value = (AstTyped *) ast_clone(a, ((AstArgument *) node)->value); + C(AstArgument, value); break; case Ast_Kind_Address_Of: - ((AstAddressOf *) nn)->expr = (AstTyped *) ast_clone(a, ((AstAddressOf *) node)->expr); + C(AstAddressOf, expr); break; case Ast_Kind_Dereference: - ((AstDereference *) nn)->expr = (AstTyped *) ast_clone(a, ((AstDereference *) node)->expr); + C(AstDereference, expr); break; case Ast_Kind_Slice: case Ast_Kind_Subscript: - ((AstSubscript *) nn)->addr = (AstTyped *) ast_clone(a, ((AstSubscript *) node)->addr); - ((AstSubscript *) nn)->expr = (AstTyped *) ast_clone(a, ((AstSubscript *) node)->expr); + C(AstSubscript, addr); + C(AstSubscript, expr); break; case Ast_Kind_Field_Access: - ((AstFieldAccess *) nn)->expr = (AstTyped *) ast_clone(a, ((AstFieldAccess *) node)->expr); + C(AstFieldAccess, expr); break; case Ast_Kind_Size_Of: - ((AstSizeOf *) nn)->so_ast_type = (AstType *) ast_clone(a, ((AstSizeOf *) node)->so_ast_type); + C(AstSizeOf, so_ast_type); break; case Ast_Kind_Align_Of: - ((AstAlignOf *) nn)->ao_ast_type = (AstType *) ast_clone(a, ((AstAlignOf *) node)->ao_ast_type); + C(AstAlignOf, ao_ast_type); break; case Ast_Kind_Struct_Literal: { @@ -215,13 +217,13 @@ AstNode* ast_clone(bh_allocator a, void* n) { } case Ast_Kind_Range_Literal: - ((AstRangeLiteral *) nn)->low = (AstTyped *) ast_clone(a, ((AstRangeLiteral *) node)->low); - ((AstRangeLiteral *) nn)->high = (AstTyped *) ast_clone(a, ((AstRangeLiteral *) node)->high); - ((AstRangeLiteral *) nn)->step = (AstTyped *) ast_clone(a, ((AstRangeLiteral *) node)->step); + C(AstRangeLiteral, low); + C(AstRangeLiteral, high); + C(AstRangeLiteral, step); break; case Ast_Kind_Return: - ((AstReturn *) nn)->expr = (AstTyped *) ast_clone(a, ((AstReturn *) node)->expr); + C(AstReturn, expr); break; case Ast_Kind_Block: @@ -229,29 +231,29 @@ AstNode* ast_clone(bh_allocator a, void* n) { break; case Ast_Kind_Defer: - ((AstDefer *) nn)->stmt = ast_clone(a, ((AstDefer *) node)->stmt); + C(AstDefer, stmt); break; case Ast_Kind_For: - ((AstFor *) nn)->var = (AstLocal *) ast_clone(a, ((AstFor *) node)->var); - ((AstFor *) nn)->iter = (AstTyped *) ast_clone(a, ((AstFor *) node)->iter); - ((AstFor *) nn)->stmt = (AstBlock *) ast_clone(a, ((AstFor *) node)->stmt); + C(AstFor, var); + C(AstFor, iter); + C(AstFor, stmt); break; case Ast_Kind_If: case Ast_Kind_While: - ((AstIfWhile *) nn)->local = (AstLocal *) ast_clone(a, ((AstIfWhile *) node)->local); - ((AstIfWhile *) nn)->assignment = (AstBinaryOp *) ast_clone(a, ((AstIfWhile *) node)->assignment); + C(AstIfWhile, local); + C(AstIfWhile, assignment); if (((AstIfWhile *) nn)->assignment) ((AstIfWhile *) nn)->assignment->left = (AstTyped *) ((AstIfWhile *) nn)->local; - ((AstIfWhile *) nn)->cond = (AstTyped *) ast_clone(a, ((AstIfWhile *) node)->cond); + C(AstIfWhile, cond); //fallthrough case Ast_Kind_Static_If: - ((AstIfWhile *) nn)->true_stmt = (AstBlock *) ast_clone(a, ((AstIfWhile *) node)->true_stmt); - ((AstIfWhile *) nn)->false_stmt = (AstBlock *) ast_clone(a, ((AstIfWhile *) node)->false_stmt); + C(AstIfWhile, true_stmt); + C(AstIfWhile, false_stmt); break; case Ast_Kind_Switch: { @@ -284,28 +286,28 @@ AstNode* ast_clone(bh_allocator a, void* n) { } case Ast_Kind_Pointer_Type: - ((AstPointerType *) nn)->elem = (AstType *) ast_clone(a, ((AstPointerType *) node)->elem); + C(AstPointerType, elem); break; case Ast_Kind_Array_Type: - ((AstArrayType *) nn)->count_expr = (AstTyped *) ast_clone(a, ((AstArrayType *) node)->count_expr); - ((AstArrayType *) nn)->elem = (AstType *) ast_clone(a, ((AstArrayType *) node)->elem); + C(AstArrayType, count_expr); + C(AstArrayType, elem); break; case Ast_Kind_Slice_Type: - ((AstSliceType *) nn)->elem = (AstType *) ast_clone(a, ((AstSliceType *) node)->elem); + C(AstSliceType, elem); break; case Ast_Kind_DynArr_Type: - ((AstDynArrType *) nn)->elem = (AstType *) ast_clone(a, ((AstDynArrType *) node)->elem); + C(AstDynArrType, elem); break; case Ast_Kind_VarArg_Type: - ((AstVarArgType *) nn)->elem = (AstType *) ast_clone(a, ((AstVarArgType *) node)->elem); + C(AstVarArgType, elem); break; case Ast_Kind_Type_Alias: - ((AstTypeAlias *) nn)->to = (AstType *) ast_clone(a, ((AstTypeAlias *) node)->to); + C(AstTypeAlias, to); break; case Ast_Kind_Struct_Type: { @@ -324,8 +326,8 @@ AstNode* ast_clone(bh_allocator a, void* n) { } case Ast_Kind_Struct_Member: - ((AstStructMember *) nn)->type_node = (AstType *) ast_clone(a, ((AstStructMember *) node)->type_node); - ((AstStructMember *) nn)->initial_value = (AstTyped *) ast_clone(a, ((AstStructMember *) node)->initial_value); + C(AstStructMember, type_node); + C(AstStructMember, initial_value); break; case Ast_Kind_Poly_Call_Type: { @@ -357,7 +359,7 @@ AstNode* ast_clone(bh_allocator a, void* n) { } case Ast_Kind_Function_Type: - ((AstFunctionType *) nn)->return_type = (AstType *) ast_clone(a, ((AstFunctionType *) node)->return_type); + C(AstFunctionType, return_type); ((AstFunctionType *) nn)->param_count = ((AstFunctionType *) node)->param_count; fori (i, 0, (i64) ((AstFunctionType *) nn)->param_count) { ((AstFunctionType *) nn)->params[i] = (AstType *) ast_clone(a, ((AstFunctionType *) node)->params[i]); @@ -366,8 +368,8 @@ AstNode* ast_clone(bh_allocator a, void* n) { case Ast_Kind_Binding: bh_printf("Cloning binding: %b\n", node->token->text, node->token->length); - ((AstTyped *) nn)->type_node = (AstType *) ast_clone(a, ((AstTyped *) node)->type_node); - ((AstBinding *) nn)->node = ast_clone(a, ((AstBinding *) node)->node); + C(AstTyped, type_node); + C(AstBinding, node); break; case Ast_Kind_Function: { @@ -398,10 +400,9 @@ AstNode* ast_clone(bh_allocator a, void* n) { break; } - case Ast_Kind_Use: { - ((AstUse *) nn)->expr = (AstTyped *) ast_clone(a, ((AstUse *) node)->expr); + case Ast_Kind_Use: + C(AstUse, expr); break; - } case Ast_Kind_Directive_Solidify: { AstDirectiveSolidify* dd = (AstDirectiveSolidify *) nn; @@ -437,34 +438,32 @@ AstNode* ast_clone(bh_allocator a, void* n) { break; } - case Ast_Kind_Named_Value: { - ((AstNamedValue *) nn)->value = (AstTyped *) ast_clone(a, ((AstNamedValue *) node)->value); + case Ast_Kind_Named_Value: + C(AstNamedValue, value); break; - } - case Ast_Kind_If_Expression: { - ((AstIfExpression *) nn)->cond = (AstTyped *) ast_clone(a, ((AstIfExpression *) node)->cond); - ((AstIfExpression *) nn)->true_expr = (AstTyped *) ast_clone(a, ((AstIfExpression *) node)->true_expr); - ((AstIfExpression *) nn)->false_expr = (AstTyped *) ast_clone(a, ((AstIfExpression *) node)->false_expr); + case Ast_Kind_If_Expression: + C(AstIfExpression, cond); + C(AstIfExpression, true_expr); + C(AstIfExpression, false_expr); break; - } - case Ast_Kind_Directive_Insert: { - ((AstDirectiveInsert *) nn)->code_expr = (AstTyped *) ast_clone(a, ((AstDirectiveInsert *) node)->code_expr); + case Ast_Kind_Directive_Insert: + C(AstDirectiveInsert, code_expr); break; - } - case Ast_Kind_Typeof: { - ((AstTypeOf *) nn)->expr = (AstTyped *) ast_clone(a, ((AstTypeOf *) node)->expr); + case Ast_Kind_Typeof: + C(AstTypeOf, expr); ((AstTypeOf *) nn)->resolved_type = NULL; break; - } } clone_depth--; return nn; } +#undef C + AstFunction* clone_function_header(bh_allocator a, AstFunction* func) { if (func->kind != Ast_Kind_Function) return NULL; diff --git a/src/onyxparser.c b/src/onyxparser.c index 0892a6cd..391ac9c8 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -2066,8 +2066,13 @@ static AstFunction* parse_function_definition(OnyxParser* parser, OnyxToken* tok parser->polymorph_context.poly_params = NULL; func_def->return_type = (AstType *) &basic_type_void; - if (consume_token_if_next(parser, Token_Type_Right_Arrow)) - func_def->return_type = parse_type(parser); + if (consume_token_if_next(parser, Token_Type_Right_Arrow)) { + if (parse_possible_directive(parser, "auto")) { + func_def->return_type = (AstType *) &basic_type_auto_return; + } else { + func_def->return_type = parse_type(parser); + } + } while (parser->curr->type == '#') { if (parse_possible_directive(parser, "intrinsic")) { diff --git a/src/onyxsymres.c b/src/onyxsymres.c index 27a28f71..d58cd4fc 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -1195,8 +1195,8 @@ void symres_entity(Entity* ent) { } report_unresolved_symbols = (context.entities.type_count[Entity_Type_Static_If] == 0 && - context.entities.type_count[Entity_Type_Use_Package] == 0); - // || context.cycle_detected; + context.entities.type_count[Entity_Type_Use_Package] == 0) + || context.cycle_detected; SymresStatus ss = Symres_Success; EntityState next_state = Entity_State_Check_Types;