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
}
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;
},
}
};
}
+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);
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;
}
}
+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;
}
}
+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 {
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] {
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;
}
// 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;
}
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,
}
#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();
// 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;
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
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;
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)) {
return Check_Error;
} else {
- return Check_Yield_Macro;
+ YIELD(call->token->pos, "Waiting for overloaded function option to pass type-checking.");
}
}
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;
// 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,
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;
return Check_Error;
} else {
- return Check_Yield_Macro;
+ YIELD(binop->token->pos, "Trying to resolve try of right hand side.");
}
}
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.");
}
}
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
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);
}
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)) {
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'.",
}
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) {
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);
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
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
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)) {
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;
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);
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);
}
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];
// 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;
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);
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;
}
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) {
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) {
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;
// 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) {
}
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) {
}
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;
// "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) {
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;
}
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;
}
} 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;
}
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;
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;
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;
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:
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: {
}
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:
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: {
}
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: {
}
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: {
}
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]);
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: {
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;
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;
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")) {
}
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;