Added basic function overloading
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 18 Jul 2020 02:56:03 +0000 (21:56 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 18 Jul 2020 02:56:03 +0000 (21:56 -0500)
include/onyxastnodes.h
onyx
progs/arrays.onyx
progs/print_funcs.onyx
src/onyxchecker.c
src/onyxparser.c
src/onyxsymres.c
src/onyxutils.c
src/onyxwasm.c

index 6e3a2366bf94c0a271e2ec84a667feecb65b0b9c..ceacab399a9f1c56d08646c578d0f9a3dc6e8e34 100644 (file)
@@ -30,10 +30,10 @@ typedef struct AstPointerType AstPointerType;
 typedef struct AstFunctionType AstFunctionType;
 
 typedef struct AstBinding AstBinding;
-typedef struct AstFunction AstFunction;
-typedef struct AstForeign AstForeign;
-typedef struct AstGlobal AstGlobal;
 typedef struct AstUse AstUse;
+typedef struct AstGlobal AstGlobal;
+typedef struct AstFunction AstFunction;
+typedef struct AstOverloadedFunction AstOverloadedFunction;
 
 typedef enum AstKind {
     Ast_Kind_Error,
@@ -42,6 +42,7 @@ typedef enum AstKind {
 
     Ast_Kind_Binding,
     Ast_Kind_Function,
+    Ast_Kind_Overloaded_Function,
     Ast_Kind_Foreign,
     Ast_Kind_Block,
     Ast_Kind_Local_Group,
@@ -255,6 +256,11 @@ struct AstFunction      {
         };
     };
 };
+struct AstOverloadedFunction {
+    AstTyped_base;
+
+    bh_arr(AstTyped *) overloads;
+};
 
 // NOTE: Simple data structure for storing what comes out of the parser
 typedef struct ParserOutput {
diff --git a/onyx b/onyx
index e31cecd7ec9539929585bb763571728fe42052b6..caa0034a88fcd8f9b213b21ddecf780df073bcd2 100755 (executable)
Binary files a/onyx and b/onyx differ
index 242462748240d41623dd86426c961371ed609f3f..c4f6bd4c694f0b1d54db518bfede4922339d7c68 100644 (file)
@@ -1,6 +1,24 @@
 use "progs/intrinsics"
 use "progs/print_funcs"
 
+global_arr :: global ^i32;
+
+min_i32 :: proc (a: i32, b: i32) -> i32 {
+    least := a;
+    if b < a least = b;
+    return least;
+}
+
+min_i64 :: proc (a: i64, b: i64) -> i64 {
+    least := a;
+    if b < a least = b;
+    return least;
+}
+
+min :: proc #overloaded {
+    min_i32, min_i64, min_f32, min_f64
+}
+
 // NOTE: in-place insertion sort
 sort :: proc (src: ^i32, len: i32) {
     i := 0;
@@ -21,17 +39,17 @@ sort :: proc (src: ^i32, len: i32) {
     }
 }
 
-global_arr :: global ^i32;
-
-print_i32arr :: proc (arr: ^i32, len: i32) {
+printarr :: proc (arr: ^i32, len: i32) {
     i := 0;
     while i < len {
-        print_i32(arr[i]);
+        print(arr[i]);
         i += 1;
     }
 }
 
 main :: proc #export {
+    print(min(10.0, 12.0));
+
     global_arr = 0 as ^i32;
     len :: 10;
 
@@ -41,11 +59,11 @@ main :: proc #export {
         i += 1;
     }
 
-    print_i32arr(global_arr, len);
+    printarr(global_arr, len);
 
     sort(global_arr, len);
 
-    print_i32(1234567);
-    print_i32arr(global_arr, len);
+    print(1234567);
+    printarr(global_arr, len);
 }
 
index 3ac27828645e6312d0af12662fa32707a4c25ba6..ac1e750ecf22a0b45305e222b798d1717e2c1490 100644 (file)
@@ -3,3 +3,11 @@ print_i32  :: proc #foreign "host" "print" (value: i32) ---
 print_f32  :: proc #foreign "host" "print" (value: f32) ---
 print_i64  :: proc #foreign "host" "print" (value: i64) ---
 print_f64  :: proc #foreign "host" "print" (value: f64) ---
+
+print :: proc #overloaded {
+    print_bool,
+    print_i32,
+    print_f32,
+    print_i64,
+    print_f64
+}
index 90a3e6cac5a5d7520dc62d331254f7b2443b595d..a61df5befb681642af9551c496e58ff4abd071e9 100644 (file)
@@ -2,7 +2,6 @@
 #include "onyxsempass.h"
 #include "onyxparser.h"
 
-static b32 check_function(SemState* state, AstFunction* func);
 static b32 check_block(SemState* state, AstBlock* block);
 static b32 check_statement_chain(SemState* state, AstNode* start);
 static b32 check_statement(SemState* state, AstNode* stmt);
@@ -14,6 +13,13 @@ static b32 check_binaryop(SemState* state, AstBinaryOp* binop);
 static b32 check_expression(SemState* state, AstTyped* expr);
 static b32 check_array_access(SemState* state, AstArrayAccess* expr);
 static b32 check_global(SemState* state, AstGlobal* global);
+static b32 check_function(SemState* state, AstFunction* func);
+static b32 check_overloaded_function(SemState* state, AstOverloadedFunction* func);
+
+static inline void fill_in_type(SemState* state, AstTyped* node) {
+    if (node->type == NULL)
+        node->type = type_build_from_ast(state->allocator, node->type_node);
+}
 
 static b32 check_return(SemState* state, AstReturn* retnode) {
     if (retnode->expr) {
@@ -71,6 +77,46 @@ static b32 check_while(SemState* state, AstWhile* whilenode) {
     return check_statement(state, whilenode->stmt);
 }
 
+static AstTyped* match_overloaded_function(SemState* state, AstCall* call, AstOverloadedFunction* ofunc) {
+    u64 param_count = 0;
+    for (AstArgument* arg = call->arguments;
+            arg != NULL;
+            arg = (AstArgument *) arg->next) param_count++;
+
+    bh_arr_each(AstTyped *, node, ofunc->overloads) {
+        AstFunction* overload = (AstFunction *) *node;
+
+        fill_in_type(state, (AstTyped *) overload);
+
+        TypeFunction* ol_type = &overload->type->Function;
+
+        if (ol_type->param_count != param_count) continue;
+
+        AstArgument* arg = call->arguments;
+        Type** param_type = ol_type->params;
+        while (arg != NULL) {
+            fill_in_type(state, (AstTyped *) arg);
+
+            if (!types_are_compatible(*param_type, arg->type)) goto no_match;
+
+            param_type++;
+            arg = (AstArgument *) arg->next;
+        }
+
+        return (AstTyped *) overload;
+
+no_match:
+        continue;
+    }
+
+    onyx_message_add(state->msgs,
+            ONYX_MESSAGE_TYPE_LITERAL,
+            call->token->pos,
+            "unable to match overloaded function");
+
+    return NULL;
+}
+
 static b32 check_call(SemState* state, AstCall* call) {
     AstFunction* callee = (AstFunction *) call->callee;
 
@@ -82,10 +128,23 @@ static b32 check_call(SemState* state, AstCall* call) {
         return 1;
     }
 
-    if (callee->type == NULL) {
-        callee->type = type_build_from_ast(state->node_allocator, callee->type_node);
+    // NOTE: Check arguments
+    AstArgument* actual_param = call->arguments;
+    while (actual_param != NULL) {
+        if (check_expression(state, (AstTyped *) actual_param)) return 1;
+        actual_param = (AstArgument *) actual_param->next;
+    }
+
+    if (callee->kind == Ast_Kind_Overloaded_Function) {
+        call->callee = (AstNode *) match_overloaded_function(state, call, (AstOverloadedFunction *) callee);
+        callee = (AstFunction *) call->callee;
+
+        if (callee == NULL) return 1;
     }
 
+    // NOTE: Build callee's type
+    fill_in_type(state, (AstTyped *) callee);
+
     if (callee->type->kind != Type_Kind_Function) {
         onyx_message_add(state->msgs,
                 ONYX_MESSAGE_TYPE_CALL_NON_FUNCTION,
@@ -160,15 +219,11 @@ static b32 check_call(SemState* state, AstCall* call) {
     call->type = callee->type->Function.return_type;
 
     AstLocal* formal_param = callee->params;
-    AstArgument* actual_param = call->arguments;
+    actual_param = call->arguments;
 
     i32 arg_pos = 0;
     while (formal_param != NULL && actual_param != NULL) {
-        if (check_expression(state, (AstTyped *) actual_param)) return 1;
-
-        if (formal_param->type == NULL) {
-            formal_param->type = type_build_from_ast(state->node_allocator, formal_param->type_node);
-        }
+        fill_in_type(state, (AstTyped *) formal_param);
 
         if (!types_are_compatible(formal_param->type, actual_param->type)) {
             onyx_message_add(state->msgs,
@@ -338,9 +393,7 @@ static b32 check_expression(SemState* state, AstTyped* expr) {
         return 1;
     }
 
-    if (expr->type == NULL) {
-        expr->type = type_build_from_ast(state->node_allocator, expr->type_node);
-    }
+    fill_in_type(state, expr);
 
     i32 retval = 0;
     switch (expr->kind) {
@@ -403,6 +456,7 @@ static b32 check_expression(SemState* state, AstTyped* expr) {
             break;
 
         case Ast_Kind_Function: break;
+        case Ast_Kind_Overloaded_Function: break;
 
         default:
             retval = 1;
@@ -414,8 +468,7 @@ static b32 check_expression(SemState* state, AstTyped* expr) {
 }
 
 static b32 check_global(SemState* state, AstGlobal* global) {
-    if (global->type == NULL)
-        global->type = type_build_from_ast(state->allocator, global->type_node);
+    fill_in_type(state, (AstTyped *) global);
 
     if (global->type == NULL) {
         onyx_message_add(state->msgs,
@@ -471,9 +524,7 @@ static b32 check_block(SemState* state, AstBlock* block) {
 
 static b32 check_function(SemState* state, AstFunction* func) {
     for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->next) {
-        if (param->type == NULL) {
-            param->type = type_build_from_ast(state->node_allocator, param->type_node);
-        }
+        fill_in_type(state, (AstTyped *) param);
 
         if (param->type == NULL) {
             onyx_message_add(state->msgs,
@@ -492,9 +543,7 @@ static b32 check_function(SemState* state, AstFunction* func) {
         }
     }
 
-    if (func->type == NULL) {
-        func->type = type_build_from_ast(state->node_allocator, func->type_node);
-    }
+    fill_in_type(state, (AstTyped *) func);
 
     if ((func->flags & Ast_Flag_Exported) != 0) {
         if ((func->flags & Ast_Flag_Foreign) != 0) {
@@ -538,16 +587,41 @@ static b32 check_function(SemState* state, AstFunction* func) {
     return 0;
 }
 
+static b32 check_overloaded_function(SemState* state, AstOverloadedFunction* func) {
+    bh_arr_each(AstTyped *, node, func->overloads) {
+        if ((*node)->kind == Ast_Kind_Overloaded_Function) {
+            onyx_message_add(state->msgs,
+                    ONYX_MESSAGE_TYPE_LITERAL,
+                    (*node)->token->pos,
+                    "overload option can not be another overloaded function (yet)");
+
+            return 1;
+        }
+
+        if ((*node)->kind != Ast_Kind_Function) {
+            onyx_message_add(state->msgs,
+                    ONYX_MESSAGE_TYPE_LITERAL,
+                    (*node)->token->pos,
+                    "overload option not function");
+
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
 static b32 check_node(SemState* state, AstNode* node) {
     switch (node->kind) {
-        case Ast_Kind_Function:     return check_function(state, (AstFunction *) node);
-        case Ast_Kind_Block:        return check_block(state, (AstBlock *) node);
-        case Ast_Kind_Return:       return check_return(state, (AstReturn *) node);
-        case Ast_Kind_If:           return check_if(state, (AstIf *) node);
-        case Ast_Kind_While:        return check_while(state, (AstWhile *) node);
-        case Ast_Kind_Call:         return check_call(state, (AstCall *) node);
-        case Ast_Kind_Binary_Op:    return check_binaryop(state, (AstBinaryOp *) node);
-        default:                    return check_expression(state, (AstTyped *) node);
+        case Ast_Kind_Function:             return check_function(state, (AstFunction *) node);
+        case Ast_Kind_Overloaded_Function:  return check_overloaded_function(state, (AstOverloadedFunction *) node);
+        case Ast_Kind_Block:                return check_block(state, (AstBlock *) node);
+        case Ast_Kind_Return:               return check_return(state, (AstReturn *) node);
+        case Ast_Kind_If:                   return check_if(state, (AstIf *) node);
+        case Ast_Kind_While:                return check_while(state, (AstWhile *) node);
+        case Ast_Kind_Call:                 return check_call(state, (AstCall *) node);
+        case Ast_Kind_Binary_Op:            return check_binaryop(state, (AstBinaryOp *) node);
+        default:                            return check_expression(state, (AstTyped *) node);
     }
 }
 
index a6c5d20a308a126aa3ad04dd34364019eb0336f4..034a6840a58010e49b85c7d002506e0721ea3b6c 100644 (file)
@@ -740,12 +740,32 @@ static b32 parse_possible_directive(OnyxParser* parser, const char* dir) {
 
 // 'proc' <directive>* <func_params> ('->' <type>)? <block>
 static AstFunction* parse_function_definition(OnyxParser* parser) {
-
     AstFunction* func_def = make_node(AstFunction, Ast_Kind_Function);
     bh_arr_new(global_heap_allocator, func_def->locals, 4);
     func_def->token = expect_token(parser, Token_Type_Keyword_Proc);
 
     while (parser->curr->type == '#') {
+        if (parse_possible_directive(parser, "overloaded")) {
+            AstOverloadedFunction* ofunc = make_node(AstOverloadedFunction, Ast_Kind_Overloaded_Function);
+            ofunc->token = func_def->token;
+
+            bh_arr_new(global_heap_allocator, ofunc->overloads, 4);
+
+            expect_token(parser, '{');
+            while (parser->curr->type != '}') {
+                AstTyped* sym_node = make_node(AstTyped, Ast_Kind_Symbol);
+                sym_node->token = expect_token(parser, Token_Type_Symbol);
+
+                bh_arr_push(ofunc->overloads, sym_node);
+
+                if (parser->curr->type != '}')
+                    expect_token(parser, ',');
+            }
+
+            consume_token(parser);
+            return (AstFunction *) ofunc;
+        }
+
         if (parse_possible_directive(parser, "intrinsic")) {
             func_def->flags |= Ast_Flag_Intrinsic;
 
@@ -913,7 +933,7 @@ static AstNode* parse_top_level_statement(OnyxParser* parser) {
                     if (global->exported_name == NULL)
                         global->exported_name = symbol;
 
-                } else {
+                } else if (node->kind != Ast_Kind_Overloaded_Function) {
                     // HACK
                     bh_arr_push(parser->results.nodes_to_process, (AstNode *) node);
                 }
index 58f988bd210dbeefa8e2655eaa989932c024d11a..37fa53071fa268ffcd271686a7c8aa1beb832d7b 100644 (file)
@@ -21,6 +21,7 @@ static b32  symres_statement(SemState* state, AstNode* stmt);
 static void symres_block(SemState* state, AstBlock* block);
 static void symres_function(SemState* state, AstFunction* func);
 static void symres_global(SemState* state, AstGlobal* global);
+static void symres_overloaded_function(SemState* state, AstOverloadedFunction* ofunc);
 
 static void symbol_introduce(SemState* state, OnyxToken* tkn, AstNode* symbol) {
     token_toggle_end(tkn);
@@ -318,6 +319,14 @@ static void symres_global(SemState* state, AstGlobal* global) {
     global->type_node = symres_type(state, global->type_node);
 }
 
+static void symres_overloaded_function(SemState* state, AstOverloadedFunction* ofunc) {
+    bh_arr_each(AstTyped *, node, ofunc->overloads) {
+        if ((*node)->kind == Ast_Kind_Symbol) {
+            *node = (AstTyped *) symbol_resolve(state, (*node)->token);
+        }
+    }
+}
+
 static void symres_top_node(SemState* state, AstNode** node) {
     switch ((*node)->kind) {
         case Ast_Kind_Call:
@@ -336,6 +345,10 @@ static void symres_top_node(SemState* state, AstNode** node) {
              symres_function(state, (AstFunction *) *node);
              break;
 
+        case Ast_Kind_Overloaded_Function:
+             symres_overloaded_function(state, (AstOverloadedFunction *) *node);
+             break;
+
         default:
              DEBUG_HERE;
              break;
index d45042ee10f678bbe9091745f08151822b3fdd5a..24487a7b1b99d2a9f06101126dd03a6cbc1fee6b 100644 (file)
@@ -15,6 +15,7 @@ static const char* ast_node_names[] = {
 
     "BINDING",
     "FUNCTION",
+    "OVERLOADED_FUNCTION",
     "FOREIGN",
     "BLOCK",
     "SCOPE",
index cccb53c56301f70879dc5f992e22ee58dd1d95ba..9ac75cedd9f3a646218da0cc60edf17749410798 100644 (file)
@@ -1213,7 +1213,7 @@ static i32 output_memorysection(OnyxWasmModule* module, bh_buffer* buff) {
     u8* leb = uint_to_uleb128((u64) 1, &leb_len);
     bh_buffer_append(&vec_buff, leb, leb_len);
 
-    output_limits(4, 20, &vec_buff);
+    output_limits(4, -1, &vec_buff);
 
     leb = uint_to_uleb128((u64) (vec_buff.length), &leb_len);
     bh_buffer_append(buff, leb, leb_len);