"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/onyx",
- "args": ["--verbose", "progs/odin_example.onyx"],
+ "args": ["--verbose", "progs/poly_solidify.onyx"],
"stopAtEntry": true,
"cwd": "~/dev/c/onyx",
"environment": [],
[ ] Add macros.
+ [ ] #solidify polymoprhic procedures.
+
API Expansion:
There are many different places where the standard API for WASI and JS
backends could be improved. Here are some of the target areas.
typedef struct AstArrayLiteral AstArrayLiteral;
typedef struct AstRangeLiteral AstRangeLiteral;
+typedef struct AstDirectiveSolidify AstDirectiveSolidify;
+
typedef struct AstReturn AstReturn;
typedef struct AstJump AstJump;
typedef struct AstUse AstUse;
Ast_Kind_Switch,
Ast_Kind_Switch_Case,
+ Ast_Kind_Directive_Solidify,
+
Ast_Kind_Count
} AstKind;
VarArgKind va_kind;
};
+struct AstDirectiveSolidify {
+ AstTyped_base;
+
+ AstPolyProc* poly_proc;
+ bh_arr(AstPolySolution) known_polyvars;
+
+ AstNode* resolved_proc;
+};
+
// Intruction Node
struct AstReturn { AstNode_base; AstTyped* expr; };
struct AstJump { AstNode_base; JumpType jump; u32 count; };
struct AstPolySolution {
AstNode* poly_sym;
Type* type;
+
+ // If `type` is null, it is filled in with this type.
+ AstType* ast_type;
};
struct AstPolyProc {
AstNode_base;
Scope *poly_scope;
bh_arr(AstPolyParam) poly_params;
+ bh_arr(AstPolySolution) known_slns;
+
AstFunction* base_func;
bh_table(AstFunction *) concrete_funcs;
};
} PolyProcLookupMethod;
AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, PolyProcLookupMethod pp_lookup, ptr actual, OnyxFilePos pos);
AstFunction* polymorphic_proc_solidify(AstPolyProc* pp, bh_arr(AstPolySolution) slns, OnyxFilePos pos);
+AstNode* polymorphic_proc_try_solidify(AstPolyProc* pp, bh_arr(AstPolySolution) slns, OnyxFilePos pos);
+
AstStructType* polymorphic_struct_lookup(AstPolyStructType* ps_type, bh_arr(Type *) params, OnyxFilePos pos);
void onyx_tokenizer_free(OnyxTokenizer* tokenizer);
void onyx_lex_tokens(OnyxTokenizer* tokenizer);
+b32 token_equals(OnyxToken* tkn1, OnyxToken* tkn2);
+
#endif
--- /dev/null
+#include_file "core/std/wasi"
+
+use package core
+
+max_f32 :: #solidify math.max { T = f32 };
+
+compose :: proc (a: $A, f: proc (A) -> $B, g: proc (B) -> $C) -> C do return g(f(a));
+
+specific_compose :: #solidify compose { A = f32, B = f32, C = u32 };
+
+main :: proc (args: [] cstr) {
+ printf("max(1, 2) = %i\n", math.max(1, 2));
+ printf("max_f32(1.0, 2.0) = %f\n", max_f32(1, 2));
+
+ // printf("max_f32(1, 2) = %i\n", max_f32(cast(u32) 1, cast(u32) 2));
+
+
+}
\ No newline at end of file
expr->flags |= Ast_Flag_Function_Used;
break;
+ case Ast_Kind_Directive_Solidify:
+ *pexpr = (AstTyped *) ((AstDirectiveSolidify *) expr)->resolved_proc;
+ break;
+
case Ast_Kind_StrLit: break;
case Ast_Kind_File_Contents: break;
case Ast_Kind_Overloaded_Function: break;
lexer_lines_processed += tokenizer->line_number - 1;
lexer_tokens_processed += bh_arr_length(tokenizer->tokens);
}
+
+b32 token_equals(OnyxToken* tkn1, OnyxToken* tkn2) {
+ if (tkn1->length != tkn2->length) return 0;
+ fori (i, 0, tkn1->length)
+ if (tkn1->text[i] != tkn2->text[i]) return 0;
+ return 1;
+}
retval = (AstTyped *) alias;
break;
}
+ else if (parse_possible_directive(parser, "solidify")) {
+ AstDirectiveSolidify* solid = make_node(AstDirectiveSolidify, Ast_Kind_Directive_Solidify);
+ solid->token = parser->curr - 1;
+
+ solid->poly_proc = (AstPolyProc *) parse_factor(parser);
+
+ solid->known_polyvars = NULL;
+ bh_arr_new(global_heap_allocator, solid->known_polyvars, 2);
+
+ expect_token(parser, '{');
+ while (parser->curr->type != '}') {
+ if (parser->hit_unexpected_token) break;
+
+ AstNode* poly_var = make_node(AstNode, Ast_Kind_Symbol);
+ poly_var->token = expect_token(parser, Token_Type_Symbol);
+
+ expect_token(parser, '=');
+ AstType* poly_type = parse_type(parser);
+
+ bh_arr_push(solid->known_polyvars, ((AstPolySolution) {
+ .poly_sym = poly_var,
+ .ast_type = poly_type,
+ .type = NULL
+ }));
+
+ if (parser->curr->type != '}')
+ expect_token(parser, ',');
+ }
+ expect_token(parser, '}');
+
+ retval = (AstTyped *) solid;
+ break;
+ }
onyx_report_error(parser->curr->pos, "invalid directive in expression.");
return NULL;
#include "onyxparser.h"
#include "onyxutils.h"
#include "onyxastnodes.h"
-
+#include "onyxerrors.h"
static void scope_enter(Scope* new_scope);
static void scope_leave();
static void symres_for(AstFor* fornode);
static void symres_switch(AstSwitch* switchnode);
static void symres_use(AstUse* use);
+static void symres_directive_solidify(AstDirectiveSolidify** psolid);
static void symres_statement_chain(AstNode** walker);
static b32 symres_statement(AstNode** stmt);
static void symres_block(AstBlock* block);
symres_array_literal((AstArrayLiteral *)(*expr));
break;
+ case Ast_Kind_Directive_Solidify:
+ symres_directive_solidify((AstDirectiveSolidify **) expr);
+ break;
+
default: break;
}
}
onyx_report_error(use->token->pos, "Cannot use this.");
}
+static void symres_directive_solidify(AstDirectiveSolidify** psolid) {
+ AstDirectiveSolidify* solid = *psolid;
+ if (solid->resolved_proc != NULL)
+ *psolid = (AstDirectiveSolidify *) solid->resolved_proc;
+
+ symres_expression((AstTyped **) &solid->poly_proc);
+ if (!solid->poly_proc || solid->poly_proc->kind != Ast_Kind_Polymorphic_Proc) {
+ onyx_report_error(solid->token->pos, "Expected polymorphic procedure in #solidify directive.");
+ return;
+ }
+
+ bh_arr_each(AstPolySolution, sln, solid->known_polyvars) {
+ sln->ast_type = symres_type(sln->ast_type);
+ sln->type = type_build_from_ast(semstate.node_allocator, sln->ast_type);
+ if (onyx_has_errors()) return;
+ }
+
+ solid->resolved_proc = polymorphic_proc_try_solidify(solid->poly_proc, solid->known_polyvars, solid->token->pos);
+
+ // NOTE: Not a DirectiveSolidify.
+ *psolid = (AstDirectiveSolidify *) solid->resolved_proc;
+ return;
+}
+
// NOTE: Returns 1 if the statment should be removed
static b32 symres_statement(AstNode** stmt) {
switch ((*stmt)->kind) {
bh_arr(AstPolySolution) slns = NULL;
bh_arr_new(global_heap_allocator, slns, bh_arr_length(pp->poly_params));
+ bh_arr_each(AstPolySolution, known_sln, pp->known_slns) bh_arr_push(slns, *known_sln);
+
bh_arr_each(AstPolyParam, param, pp->poly_params) {
+ b32 already_solved = 0;
+ bh_arr_each(AstPolySolution, known_sln, pp->known_slns) {
+ if (token_equals(param->poly_sym->token, known_sln->poly_sym->token)) {
+ already_solved = 1;
+ break;
+ }
+ }
+ if (already_solved) continue;
+
Type* actual_type;
if (pp_lookup == PPLM_By_Call) {
return func;
}
+// NOTE: This can return either a AstFunction or an AstPolyProc, depending if enough parameters were
+// supplied to remove all the polymorphic variables from the function.
+AstNode* polymorphic_proc_try_solidify(AstPolyProc* pp, bh_arr(AstPolySolution) slns, OnyxFilePos pos) {
+ i32 valid_argument_count = 0;
+
+ bh_arr_each(AstPolySolution, sln, slns) {
+ b32 found_match = 0;
+
+ bh_arr_each(AstPolyParam, param, pp->poly_params) {
+ if (token_equals(sln->poly_sym->token, param->poly_sym->token)) {
+ found_match = 1;
+ break;
+ }
+ }
+
+ if (found_match) {
+ valid_argument_count++;
+ } else {
+ onyx_report_error(pos, "'%b' is not a type variable of '%b'.",
+ sln->poly_sym->token->text, sln->poly_sym->token->length,
+ pp->token->text, pp->token->length);
+ return (AstNode *) pp;
+ }
+ }
+
+ if (valid_argument_count == bh_arr_length(pp->poly_params)) {
+ return (AstNode *) polymorphic_proc_solidify(pp, slns, pos);
+
+ } else {
+ // HACK: Some of these initializations assume that the entity for this polyproc has
+ // made it through the symbol resolution phase.
+ // - brendanfh 2020/12/25
+ AstPolyProc* new_pp = onyx_ast_node_new(semstate.node_allocator, sizeof(AstPolyProc), Ast_Kind_Polymorphic_Proc);
+ new_pp->token = pp->token; // TODO: Change this to be the solidify->token
+ new_pp->base_func = pp->base_func;
+ new_pp->poly_scope = new_pp->poly_scope;
+ new_pp->flags = pp->flags;
+ new_pp->poly_params = pp->poly_params;
+
+ new_pp->known_slns = NULL;
+ bh_arr_new(global_heap_allocator, new_pp->known_slns, bh_arr_length(pp->known_slns) + bh_arr_length(slns));
+
+ bh_arr_each(AstPolySolution, sln, pp->known_slns) bh_arr_push(new_pp->known_slns, *sln);
+ bh_arr_each(AstPolySolution, sln, slns) bh_arr_push(new_pp->known_slns, *sln);
+
+ return (AstNode *) new_pp;
+ }
+}
+
AstStructType* polymorphic_struct_lookup(AstPolyStructType* ps_type, bh_arr(Type *) params, OnyxFilePos pos) {
// @Cleanup