use package core.intrinsics.onyx { __zero_value, __initialize }
}
-Map :: struct (K: type_expr, V: type_expr) {
+#private_file {
+ ValidKey :: interface (T: type_expr) {
+ hash.to_u32(T);
+ T == T;
+ }
+}
+
+Map :: struct (K: type_expr, V: type_expr) where ValidKey(K) {
allocator : Allocator;
hashes : [] i32;
NODE(Param) \
NODE(Function) \
NODE(OverloadedFunction) \
+ NODE(Interface) \
+ NODE(Constraint) \
\
NODE(PolyParam) \
NODE(PolySolution) \
Ast_Kind_Function,
Ast_Kind_Overloaded_Function,
Ast_Kind_Polymorphic_Proc,
+ Ast_Kind_Interface,
+ Ast_Kind_Constraint,
+ Ast_Kind_Constraint_Sentinel,
Ast_Kind_Block,
Ast_Kind_Local,
Ast_Kind_Global,
Block_Rule_Do_Block = Block_Rule_New_Scope | Block_Rule_Clear_Defer | Block_Rule_Override_Return | Block_Rule_Emit_Instructions,
} BlockRule;
+typedef enum ConstraintCheckStatus {
+ Constraint_Check_Status_Queued,
+ Constraint_Check_Status_Failed,
+ Constraint_Check_Status_Success,
+} ConstraintCheckStatus;
+
+typedef struct ConstraintContext {
+ bh_arr(AstConstraint *) constraints;
+ ConstraintCheckStatus *constraint_checks;
+ b32 constraints_met : 1;
+} ConstraintContext;
+
+
typedef struct Arguments Arguments;
struct Arguments {
bh_arr(AstTyped *) values;
struct Entity* entity_type;
struct Entity* entity_defaults;
+ ConstraintContext constraints;
+
b32 stcache_is_valid : 1;
b32 is_union : 1;
};
struct Entity* entity_header;
struct Entity* entity_body;
+ ConstraintContext constraints;
+
b32 is_exported : 1;
b32 is_foreign : 1;
b32 is_intrinsic : 1;
bh_imap all_overloads;
};
+// @CLEANUP: Is this really necessary?
+typedef struct InterfaceParam {
+ OnyxToken *token;
+ AstType *type_node;
+ Type *type;
+} InterfaceParam;
+
+struct AstInterface {
+ AstTyped_base;
+ char *name;
+
+ bh_arr(InterfaceParam) params;
+ bh_arr(AstTyped *) exprs;
+};
+
+typedef enum ConstraintPhase {
+ Constraint_Phase_Waiting_To_Be_Queued,
+ Constraint_Phase_Cloning_Expressions,
+ Constraint_Phase_Checking_Expressions,
+ Constraint_Phase_Finished,
+} ConstraintPhase;
+
+struct AstConstraint {
+ AstNode_base;
+
+ ConstraintPhase phase;
+
+ AstInterface *interface;
+ bh_arr(AstType *) type_args;
+
+ ConstraintCheckStatus *report_status;
+
+ Scope* scope;
+ bh_arr(AstTyped *) exprs;
+ u32 expr_idx;
+};
+
+
struct AstPackage {
AstTyped_base;
Entity_State_Check_Types,
Entity_State_Code_Gen,
Entity_State_Finalized,
+ Entity_State_Failed,
Entity_State_Count,
} EntityState;
Entity_Type_Type_Alias,
Entity_Type_Memory_Reservation_Type,
Entity_Type_Use,
+ Entity_Type_Interface,
+ Entity_Type_Constraint_Check,
Entity_Type_Polymorphic_Proc,
Entity_Type_Macro,
Entity_Type_Foreign_Function_Header,
AstPolyProc *poly_proc;
AstMacro *macro;
AstUse *use;
+ AstInterface *interface;
+ AstConstraint *constraint;
};
} Entity;
Token_Type_Keyword_Switch,
Token_Type_Keyword_Fallthrough,
Token_Type_Keyword_Macro,
+ Token_Type_Keyword_Interface,
+ Token_Type_Keyword_Where,
Token_Type_Right_Arrow,
Token_Type_Left_Arrow,
b32 hit_unexpected_token : 1;
- // If this is 1, then things that look like calls with immediately be parsed as calls.
- // However, if this is 0 then things that look like procedure definitions after expressions,
- // will be parsed as procedure definitions.
- b32 greedily_consume_calls : 1;
+ b32 parse_calls : 1;
} OnyxParser;
const char* onyx_ast_node_kind_string(AstKind kind);
# strings in YAML. When using single quoted strings, only single quotes
# need to be escaped: this is done by using two single quotes next to each
# other.
- - match: '\b(package|struct|use|global|enum|if|elseif|else|for|while|do|break|continue|fallthrough|return|as|cast|sizeof|alignof|typeof|defer|switch|case|macro)\b'
+ - match: '\b(package|struct|interface|use|where|global|enum|if|elseif|else|for|while|do|break|continue|fallthrough|return|as|cast|sizeof|alignof|typeof|defer|switch|case|macro)\b'
scope: keyword.control.onyx
- match: '\b(bool|void|i8|u8|i16|u16|i32|u32|i64|u64|f32|f64|rawptr|str|cstr|range|type_expr|any)\b'
"FUNCTION",
"OVERLOADED_FUNCTION",
"POLYMORPHIC PROC",
+ "INTERFACE",
+ "CONSTRAINT",
+ "CONSTRAINT SENTITEL",
"BLOCK",
"LOCAL",
"GLOBAL",
"Resolve Symbols",
"Check Types",
"Code Gen",
+ "Failed",
"Finalized",
};
"Type Alias",
"Memory Reservation Type",
"Use",
+ "Interface",
+ "Constraint Check",
"Polymorphic Proc",
"Macro",
"Foreign_Function Header",
+ "Temporary Function Header",
"Function Header",
"Global Header",
"Process Directive",
Check_Errors_Start,
Check_Return_To_Symres, // Return this node for further symres processing
Check_Yield_Macro,
+ Check_Failed, // The node is done processing and should be put in the state of Failed.
Check_Error, // There was an error when checking the node
} CheckStatus;
CheckStatus check_type(AstType* type);
CheckStatus check_insert_directive(AstDirectiveInsert** pinsert);
CheckStatus check_do_block(AstDoBlock** pdoblock);
+CheckStatus check_constraint(AstConstraint *constraint);
+CheckStatus check_constraint_context(ConstraintContext *cc, OnyxFilePos pos);
// HACK HACK HACK
b32 expression_types_must_be_known = 0;
AstFunction* callee=NULL;
CHECK(resolve_callee, call, (AstTyped **) &callee);
+ if (callee->kind == Ast_Kind_Function) {
+ if (callee->constraints.constraints != NULL && callee->constraints.constraints_met == 0) {
+ YIELD(call->token->pos, "Waiting for constraints to be checked on callee.");
+ }
+ }
+
i32 arg_count = get_argument_buffer_size(&callee->type->Function, &call->args);
arguments_ensure_length(&call->args, arg_count);
case Ast_Kind_Package: break;
case Ast_Kind_Error: break;
case Ast_Kind_Unary_Field_Access: break;
+ case Ast_Kind_Constraint_Sentinel: break;
// NOTE: The only way to have an Intrinsic_Call node is to have gone through the
// checking of a call node at least once.
if (s_node->entity_defaults && s_node->entity_defaults->state < Entity_State_Check_Types)
YIELD(s_node->token->pos, "Waiting for struct member defaults to pass symbol resolution.");
+ if (s_node->constraints.constraints) {
+ CHECK(constraint_context, &s_node->constraints, s_node->token->pos);
+ }
+
bh_arr_each(AstStructMember *, smem, s_node->members) {
if ((*smem)->type_node != NULL) {
CHECK(type, (*smem)->type_node);
}
CheckStatus check_temp_function_header(AstFunction* func) {
- CHECK(function_header, func);
+ CheckStatus cs = check_function_header(func);
+ if (cs == Check_Error) {
+ onyx_clear_errors();
+ return Check_Failed;
+ }
+
+ if (cs != Check_Success) return cs;
+
return Check_Complete;
}
if (func->return_type != NULL) CHECK(type, func->return_type);
+ if (func->constraints.constraints != NULL) {
+ CHECK(constraint_context, &func->constraints, func->token->pos);
+ }
+
func->type = type_build_function_type(context.ast_alloc, func);
if (func->type == NULL) YIELD(func->token->pos, "Waiting for function type to be constructed");
return Check_Success;
}
+CheckStatus check_constraint(AstConstraint *constraint) {
+ switch (constraint->phase) {
+ case Constraint_Phase_Cloning_Expressions: {
+ if (constraint->interface->kind != Ast_Kind_Interface) {
+ // CLEANUP: This error message might not look totally right in some cases.
+ ERROR_(constraint->token->pos, "'%b' is not an interface.", constraint->token->text, constraint->token->length);
+ }
+
+ bh_arr_new(global_heap_allocator, constraint->exprs, bh_arr_length(constraint->interface->exprs));
+ bh_arr_each(AstTyped *, expr, constraint->interface->exprs) {
+ bh_arr_push(constraint->exprs, (AstTyped *) ast_clone(context.ast_alloc, (AstNode *) *expr));
+ }
+
+ assert(constraint->interface->entity && constraint->interface->entity->scope);
+
+ constraint->scope = scope_create(context.ast_alloc, constraint->interface->entity->scope, constraint->token->pos);
+
+ fori (i, 0, bh_arr_length(constraint->interface->params)) {
+ InterfaceParam *ip = &constraint->interface->params[i];
+
+ AstTyped *sentinel = onyx_ast_node_new(context.ast_alloc, sizeof(AstTyped), Ast_Kind_Constraint_Sentinel);
+ sentinel->token = ip->token;
+ sentinel->type_node = constraint->type_args[i];
+
+ symbol_introduce(constraint->scope, ip->token, (AstNode *) sentinel);
+ }
+
+ assert(constraint->entity);
+ constraint->entity->scope = constraint->scope;
+
+ constraint->phase = Constraint_Phase_Checking_Expressions;
+ return Check_Return_To_Symres;
+ }
+
+ case Constraint_Phase_Checking_Expressions: {
+ fori (i, constraint->expr_idx, bh_arr_length(constraint->exprs)) {
+ CheckStatus cs = check_expression(&constraint->exprs[i]);
+ if (cs == Check_Return_To_Symres || cs == Check_Yield_Macro) {
+ return cs;
+ }
+
+ if (cs == Check_Error) {
+ // HACK HACK HACK
+ onyx_clear_errors();
+
+ // onyx_report_error(constraint->interface->exprs[i]->token->pos, "This constraint was not satisfied.");
+ // onyx_report_error(constraint->token->pos, "Here was where the interface was used.");
+ *constraint->report_status = Constraint_Check_Status_Failed;
+ return Check_Failed;
+ }
+
+ constraint->expr_idx++;
+ }
+
+ *constraint->report_status = Constraint_Check_Status_Success;
+ return Check_Complete;
+ }
+ }
+
+ return Check_Success;
+}
+
+CheckStatus check_constraint_context(ConstraintContext *cc, OnyxFilePos pos) {
+ if (cc->constraint_checks) {
+ if (cc->constraints_met == 1) return Check_Success;
+
+ fori (i, 0, bh_arr_length(cc->constraints)) {
+ if (cc->constraint_checks[i] == Constraint_Check_Status_Failed) {
+ AstConstraint *constraint = cc->constraints[i];
+ char constraint_map[512] = {0};
+ fori (i, 0, bh_arr_length(constraint->type_args)) {
+ if (i != 0) strncat(constraint_map, ", ", 511);
+
+ OnyxToken* symbol = constraint->interface->params[i].token;
+ token_toggle_end(symbol);
+ strncat(constraint_map, symbol->text, 511);
+ token_toggle_end(symbol);
+
+ strncat(constraint_map, " is of type '", 511);
+ strncat(constraint_map, type_get_name(type_build_from_ast(context.ast_alloc, constraint->type_args[i])), 511);
+ strncat(constraint_map, "'", 511);
+ }
+
+ onyx_report_error(constraint->exprs[constraint->expr_idx]->token->pos, "Failed to satisfy constraint where %s.", constraint_map);
+ onyx_report_error(constraint->token->pos, "Here is where the interface was used.");
+ return Check_Error;
+ }
+
+ if (cc->constraint_checks[i] == Constraint_Check_Status_Queued) {
+ YIELD(pos, "Waiting for constraints to be checked.");
+ }
+ }
+
+ cc->constraints_met = 1;
+ return Check_Success;
+
+ } else {
+ u32 count = bh_arr_length(cc->constraints);
+ ConstraintCheckStatus *ccs = bh_alloc_array(context.ast_alloc, ConstraintCheckStatus, count);
+
+ cc->constraint_checks = ccs;
+
+ fori (i, 0, count) {
+ ccs[i] = Constraint_Check_Status_Queued;
+ cc->constraints[i]->report_status = &ccs[i];
+ cc->constraints[i]->phase = Constraint_Phase_Cloning_Expressions;
+
+ add_entities_for_node(NULL, (AstNode *) cc->constraints[i], NULL, NULL);
+ }
+
+ return Check_Yield_Macro;
+ }
+}
+
CheckStatus check_node(AstNode* node) {
switch (node->kind) {
case Ast_Kind_Function: return check_function((AstFunction *) node);
case Entity_Type_Memory_Reservation_Type: cs = check_memres_type(ent->mem_res); break;
case Entity_Type_Memory_Reservation: cs = check_memres(ent->mem_res); break;
case Entity_Type_Static_If: cs = check_static_if(ent->static_if); break;
- case Entity_Type_Macro: cs = check_macro(ent->macro);
+ case Entity_Type_Macro: cs = check_macro(ent->macro); break;
+ case Entity_Type_Constraint_Check: cs = check_constraint(ent->constraint); break;
case Entity_Type_Expression:
cs = check_expression(&ent->expr);
if (cs == Check_Success) ent->state = Entity_State_Code_Gen;
if (cs == Check_Complete) ent->state = Entity_State_Finalized;
if (cs == Check_Return_To_Symres) ent->state = Entity_State_Resolve_Symbols;
+ if (cs == Check_Failed) ent->state = Entity_State_Failed;
if (cs == Check_Yield_Macro) ent->macro_attempts++;
else {
ent->macro_attempts = 0;
case Ast_Kind_If_Expression: return sizeof(AstIfExpression);
case Ast_Kind_Directive_Insert: return sizeof(AstDirectiveInsert);
case Ast_Kind_Do_Block: return sizeof(AstDoBlock);
+ case Ast_Kind_Constraint: return sizeof(AstConstraint);
case Ast_Kind_Count: return 0;
}
bh_arr_each(AstTyped *, tag, ss->meta_tags) {
bh_arr_push(ds->meta_tags, (AstTyped *) ast_clone(a, *tag));
}
+
+ if (ss->constraints.constraints) {
+ memset(&ds->constraints, 0, sizeof(ConstraintContext));
+ bh_arr_new(global_heap_allocator, ds->constraints.constraints, bh_arr_length(ss->constraints.constraints));
+
+ bh_arr_each(AstConstraint *, constraint, ss->constraints.constraints) {
+ bh_arr_push(ds->constraints.constraints, (AstConstraint *) ast_clone(a, (AstNode *) *constraint));
+ }
+ }
ds->stcache = NULL;
break;
bh_arr_push(df->params, new_param);
}
+ if (sf->constraints.constraints) {
+ memset(&df->constraints, 0, sizeof(ConstraintContext));
+ bh_arr_new(global_heap_allocator, df->constraints.constraints, bh_arr_length(sf->constraints.constraints));
+
+ bh_arr_each(AstConstraint *, constraint, sf->constraints.constraints) {
+ bh_arr_push(df->constraints.constraints, (AstConstraint *) ast_clone(a, (AstNode *) *constraint));
+ }
+ }
+
+ break;
+ }
+
+ case Ast_Kind_Constraint: {
+ C(AstConstraint, interface);
+
+ AstConstraint* dc = (AstConstraint *) nn;
+ AstConstraint* sc = (AstConstraint *) node;
+
+ dc->type_args = NULL;
+ bh_arr_new(global_heap_allocator, dc->type_args, bh_arr_length(sc->type_args));
+
+ bh_arr_each(AstType *, type_arg, sc->type_args) {
+ bh_arr_push(dc->type_args, (AstType *) ast_clone(a, (AstNode *) *type_arg));
+ }
+
break;
}
bh_arr_push(new_func->params, new_param);
}
+ if (func->constraints.constraints) {
+ memset(&new_func->constraints, 0, sizeof(ConstraintContext));
+ bh_arr_new(global_heap_allocator, new_func->constraints.constraints, bh_arr_length(func->constraints.constraints));
+
+ bh_arr_each(AstConstraint *, constraint, func->constraints.constraints) {
+ bh_arr_push(new_func->constraints.constraints, (AstConstraint *) ast_clone(a, (AstNode *) *constraint));
+ }
+ }
+
return new_func;
}
break;
}
+ case Ast_Kind_Interface: {
+ ent.type = Entity_Type_Interface;
+ ent.interface = (AstInterface *) node;
+ ent.state = Entity_State_Resolve_Symbols;
+ ENTITY_INSERT(ent);
+ break;
+ }
+
+ case Ast_Kind_Constraint: {
+ ent.type = Entity_Type_Constraint_Check;
+ ent.constraint = (AstConstraint *) node;
+ ent.state = Entity_State_Resolve_Symbols;
+ ENTITY_INSERT(ent);
+ break;
+ }
+
default: {
ent.type = Entity_Type_Expression;
ent.expr = (AstTyped *) node;
"case",
"fallthrough",
"macro",
+ "interface",
+ "where",
"->",
"<-",
break;
case 'i':
LITERAL_TOKEN("if", 1, Token_Type_Keyword_If);
+ LITERAL_TOKEN("interface", 1, Token_Type_Keyword_Interface);
break;
case 'm':
LITERAL_TOKEN("macro", 1, Token_Type_Keyword_Macro);
break;
case 'w':
LITERAL_TOKEN("while", 1, Token_Type_Keyword_While);
+ LITERAL_TOKEN("where", 1, Token_Type_Keyword_Where);
break;
case '-':
static const char* state_colors[] = {
"\e[91m", "\e[93m", "\e[94m", "\e[93m",
- "\e[97m", "\e[95m", "\e[96m", "\e[92m",
+ "\e[97m", "\e[95m", "\e[96m", "\e[92m", "\e[91m",
};
printf("\e[2;1H");
if (onyx_has_errors()) return ONYX_COMPILER_PROGRESS_ERROR;
- if (ent->state != Entity_State_Finalized)
+ if (ent->state != Entity_State_Finalized && ent->state != Entity_State_Failed)
entity_heap_insert_existing(&context.entities, ent);
}
static AstTypeOf* parse_typeof(OnyxParser* parser);
static AstStructType* parse_struct(OnyxParser* parser);
static AstInterface* parse_interface(OnyxParser* parser);
+static AstConstraint* parse_constraint(OnyxParser* parser);
+static void parse_constraints(OnyxParser* parser, ConstraintContext *constraints);
static void parse_function_params(OnyxParser* parser, AstFunction* func);
static b32 parse_possible_directive(OnyxParser* parser, const char* dir);
static b32 parse_possible_function_definition_no_consume(OnyxParser* parser);
}
case '(': {
- if (!parser->greedily_consume_calls) {
- if (parse_possible_function_definition_no_consume(parser)) goto factor_parsed;
- if (parse_possible_quick_function_definition_no_consume(parser)) goto factor_parsed;
- }
+ if (!parser->parse_calls) goto factor_parsed;
AstCall* call_node = make_node(AstCall, Ast_Kind_Call);
call_node->token = expect_token(parser, '(');
*next_insertion = (AstType *) field;
}
- if (parser->curr->type == '(') {
+ if (parser->curr->type == '(' && parser->parse_calls) {
OnyxToken* paren_token = expect_token(parser, '(');
bh_arr(AstNode *) params = NULL;
poly_struct->base_struct = s_node;
}
+ if (parser->curr->type == Token_Type_Keyword_Where) {
+ parse_constraints(parser, &s_node->constraints);
+ }
+
bh_arr_new(global_heap_allocator, s_node->members, 4);
while (parser->curr->type == '#') {
}
}
+static AstInterface* parse_interface(OnyxParser* parser) {
+ AstInterface *interface = make_node(AstInterface, Ast_Kind_Interface);
+ interface->token = expect_token(parser, Token_Type_Keyword_Interface);
+
+ bh_arr_new(global_heap_allocator, interface->params, 2);
+
+ expect_token(parser, '(');
+ while (!consume_token_if_next(parser, ')')) {
+ if (parser->hit_unexpected_token) return interface;
+
+ InterfaceParam ip;
+ ip.token = expect_token(parser, Token_Type_Symbol);
+ expect_token(parser, ':');
+ ip.type_node = parse_type(parser);
+
+ bh_arr_push(interface->params, ip);
+
+ if (parser->curr->type != ')')
+ expect_token(parser, ',');
+ }
+
+ bh_arr_new(global_heap_allocator, interface->exprs, 2);
+
+ expect_token(parser, '{');
+ while (!consume_token_if_next(parser, '}')) {
+ if (parser->hit_unexpected_token) return interface;
+
+ AstTyped *expr = parse_expression(parser, 0);
+ bh_arr_push(interface->exprs, expr);
+
+ expect_token(parser, ';');
+ }
+
+ return interface;
+}
+
+static AstConstraint* parse_constraint(OnyxParser* parser) {
+ AstConstraint* constraint = make_node(AstConstraint, Ast_Kind_Constraint);
+
+ parser->parse_calls = 0;
+ constraint->interface = (AstInterface *) parse_factor(parser);
+ parser->parse_calls = 1;
+
+ constraint->token = constraint->interface->token;
+
+ bh_arr_new(global_heap_allocator, constraint->type_args, 2);
+
+ expect_token(parser, '(');
+ while (!consume_token_if_next(parser, ')')) {
+ if (parser->hit_unexpected_token) return constraint;
+
+ AstType* type_node = parse_type(parser);
+ bh_arr_push(constraint->type_args, type_node);
+
+ if (parser->curr->type != ')')
+ expect_token(parser, ',');
+ }
+
+ return constraint;
+}
+
+static void parse_constraints(OnyxParser* parser, ConstraintContext *out_constraints) {
+ bh_arr_new(global_heap_allocator, out_constraints->constraints, 2);
+
+ expect_token(parser, Token_Type_Keyword_Where);
+
+ do {
+ AstConstraint *constraint = parse_constraint(parser);
+ if (parser->hit_unexpected_token) return;
+
+ bh_arr_push(out_constraints->constraints, constraint);
+ } while (consume_token_if_next(parser, ','));
+}
+
static void parse_function_params(OnyxParser* parser, AstFunction* func) {
expect_token(parser, '(');
}
}
+ if (parser->curr->type == Token_Type_Keyword_Where) {
+ parse_constraints(parser, &func_def->constraints);
+ }
+
while (parser->curr->type == '#') {
if (parse_possible_directive(parser, "intrinsic")) {
func_def->is_intrinsic = 1;
}
static AstTyped* parse_top_level_expression(OnyxParser* parser) {
- if (parser->curr->type == Token_Type_Keyword_Global) return parse_global_declaration(parser);
- if (parser->curr->type == Token_Type_Keyword_Struct) return (AstTyped *) parse_struct(parser);
- if (parser->curr->type == Token_Type_Keyword_Enum) return (AstTyped *) parse_enum_declaration(parser);
- if (parser->curr->type == Token_Type_Keyword_Macro) return (AstTyped *) parse_macro(parser);
+ if (parser->curr->type == Token_Type_Keyword_Global) return parse_global_declaration(parser);
+ if (parser->curr->type == Token_Type_Keyword_Struct) return (AstTyped *) parse_struct(parser);
+ if (parser->curr->type == Token_Type_Keyword_Interface) return (AstTyped *) parse_interface(parser);
+ if (parser->curr->type == Token_Type_Keyword_Enum) return (AstTyped *) parse_enum_declaration(parser);
+ if (parser->curr->type == Token_Type_Keyword_Macro) return (AstTyped *) parse_macro(parser);
if (parse_possible_directive(parser, "type")) {
AstTypeAlias* alias = make_node(AstTypeAlias, Ast_Kind_Type_Alias);
case Ast_Kind_StrLit:
break;
+ case Ast_Kind_Interface:
case Ast_Kind_Struct_Type:
case Ast_Kind_Poly_Struct_Type:
case Ast_Kind_Enum_Type:
AstDirectiveAddOverload *add_overload = make_node(AstDirectiveAddOverload, Ast_Kind_Directive_Add_Overload);
add_overload->token = dir_token;
- parser->greedily_consume_calls = 0;
+ parser->parse_calls = 0;
add_overload->overloaded_function = (AstNode *) parse_expression(parser, 0);
- parser->greedily_consume_calls = 1;
+ parser->parse_calls = 1;
if (parse_possible_directive(parser, "precedence")) {
AstNumLit* pre = parse_int_literal(parser);
parser.alternate_entity_placement_stack = NULL;
parser.current_symbol_stack = NULL;
parser.scope_flags = NULL;
- parser.greedily_consume_calls = 1;
+ parser.parse_calls = 1;
parser.polymorph_context = (PolymorphicContext) {
.root_node = NULL,
// NOTE: This function adds a solidified function to the entity heap for it to be processed
// later. It optionally can start the function header entity at the code generation state if
// the header has already been processed.
-static b32 add_solidified_function_entities(AstSolidifiedFunction solidified_func, b32 header_already_processed) {
+static b32 add_solidified_function_entities(AstSolidifiedFunction solidified_func) {
solidified_func.func->flags |= Ast_Flag_Function_Used;
solidified_func.func->flags |= Ast_Flag_From_Polymorphism;
- EntityState header_start_state = Entity_State_Resolve_Symbols;
- if (header_already_processed) header_start_state = Entity_State_Code_Gen;
-
Entity func_header_entity = {
- .state = header_start_state,
+ .state = Entity_State_Resolve_Symbols,
.type = Entity_Type_Function_Header,
.function = solidified_func.func,
.package = NULL,
// header. This should never be the case in this situation, since the header would
// have to have successfully passed type checking before it would become a solidified
// procedure.
- assert(add_solidified_function_entities(solidified_func, 1));
+ assert(add_solidified_function_entities(solidified_func));
solidified_func.func->flags &= ~Ast_Flag_Incomplete_Body;
}
// NOTE: Cache the function for later use, reducing duplicate functions.
bh_table_put(AstSolidifiedFunction, pp->concrete_funcs, unique_key, solidified_func);
- add_solidified_function_entities(solidified_func, 0);
+ add_solidified_function_entities(solidified_func);
return (AstFunction *) &node_that_signals_a_yield;
}
solidified_func = generate_solidified_function(pp, slns, NULL, 1);
}
- if (solidified_func.func_header_entity && solidified_func.func_header_entity->state == Entity_State_Finalized) return solidified_func.func;
+ if (solidified_func.func_header_entity) {
+ if (solidified_func.func_header_entity->state == Entity_State_Finalized) return solidified_func.func;
+ if (solidified_func.func_header_entity->state == Entity_State_Failed) return NULL;
+
+ return (AstFunction *) &node_that_signals_a_yield;
+ }
Entity func_header_entity = {
.state = Entity_State_Resolve_Symbols,
static SymresStatus symres_struct_defaults(AstType* st);
static SymresStatus symres_static_if(AstIf* static_if);
static SymresStatus symres_macro(AstMacro* macro);
+static SymresStatus symres_constraint(AstConstraint* constraint);
static void scope_enter(Scope* new_scope) {
curr_scope = new_scope;
scope_enter(s_node->scope);
}
+ if (s_node->constraints.constraints) {
+ bh_arr_each(AstConstraint *, constraint, s_node->constraints.constraints) {
+ SYMRES(constraint, *constraint);
+ }
+ }
+
fori (i, 0, bh_arr_length(s_node->members)) {
AstStructMember *member = s_node->members[i];
onyx_report_error(func->token->pos, "Return type is not a type.");
}
+ if (func->constraints.constraints != NULL) {
+ bh_arr_each(AstConstraint *, constraint, func->constraints.constraints) {
+ SYMRES(constraint, *constraint);
+ }
+ }
+
scope_leave();
return Symres_Success;
return Symres_Success;
}
+static SymresStatus symres_constraint(AstConstraint* constraint) {
+ switch (constraint->phase) {
+ case Constraint_Phase_Waiting_To_Be_Queued: {
+ SYMRES(expression, (AstTyped **) &constraint->interface);
+
+ bh_arr_each(AstType *, type_arg, constraint->type_args) {
+ SYMRES(type, type_arg);
+ }
+
+ return Symres_Success;
+ }
+
+ case Constraint_Phase_Checking_Expressions: {
+ fori (i, constraint->expr_idx, bh_arr_length(constraint->exprs)) {
+ SYMRES(expression, &constraint->exprs[i]);
+ }
+
+ return Symres_Success;
+ }
+ }
+
+ return Symres_Success;
+}
+
void symres_entity(Entity* ent) {
Scope* old_scope = NULL;
if (ent->scope) {
case Entity_Type_Struct_Member_Default: ss = symres_struct_defaults((AstType *) ent->type_alias); break;
case Entity_Type_Process_Directive: ss = symres_process_directive((AstNode *) ent->expr); break;
case Entity_Type_Macro: ss = symres_macro(ent->macro); break;
+ case Entity_Type_Constraint_Check: ss = symres_constraint(ent->constraint); break;
default: break;
}