From: Brendan Hansen Date: Fri, 5 Feb 2021 19:44:09 +0000 (-0600) Subject: made method call syntax more useful X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=045739d24a5780bf1a4a8fba026202a91a41b0df;p=onyx.git made method call syntax more useful --- diff --git a/bin/onyx b/bin/onyx index 54b3bfd9..a2d9e6ea 100755 Binary files a/bin/onyx and b/bin/onyx differ diff --git a/core/math.onyx b/core/math.onyx index 08a5d3c7..ff7ab779 100644 --- a/core/math.onyx +++ b/core/math.onyx @@ -139,6 +139,8 @@ atanh :: (t: $T) -> T { // ln(x) = ln(2^n * v) = n * ln(2) + ln(v), v is in [1, 2] // +// FIX: This definition is very wrong. It casts E to be whatever the type of the argument is, +// which if it is an integer, will be 2! This should always return a floating point number! exp :: (p: $T) -> T do return pow(base = cast(T) E, p = p); pow :: proc { @@ -224,10 +226,10 @@ log :: (a: $T, base: $R) -> T { // operation first, and then default to a polymoprhic function that works on any type. // The clunky part about these at the moment is that, if you wanted to pass 'max' to // a procedure, you would have to pass 'max_poly' instead, because overloaded functions -// are not resolved when used by value, i.e. foo : (f32) -> f32 = math.max; Even if they -// would be however, the fact that these overloads are intrinsic means they cannot be -// reference from the element section and therefore cannot be passed around or used as -// values. +// are not resolved when used by value, i.e. foo : (f32, f32) -> f32 = math.max; Even if +// they would be however, the fact that these overloads are intrinsic means they cannot +// be reference from the element section and therefore cannot be passed around or used +// as values. max :: proc { wasm.max_f32, wasm.max_f64, max_poly } max_poly :: (a: $T, b: T) -> T { if a >= b do return a; diff --git a/include/onyxutils.h b/include/onyxutils.h index 312ed66a..90963f3f 100644 --- a/include/onyxutils.h +++ b/include/onyxutils.h @@ -20,6 +20,7 @@ void symbol_builtin_introduce(Scope* scope, char* sym, AstNode *node); void symbol_subpackage_introduce(Scope* scope, OnyxToken* sym, AstPackage *node); AstNode* symbol_raw_resolve(Scope* start_scope, char* sym); AstNode* symbol_resolve(Scope* start_scope, OnyxToken* tkn); +AstNode* try_symbol_raw_resolve_from_node(AstNode* node, char* symbol); AstNode* try_symbol_resolve_from_node(AstNode* node, OnyxToken* token); u32 char_to_base16_value(char x); diff --git a/onyx.exe b/onyx.exe index 509874ee..09b90cbc 100644 Binary files a/onyx.exe and b/onyx.exe differ diff --git a/src/onyxchecker.c b/src/onyxchecker.c index df291d41..25bd07cf 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -17,8 +17,8 @@ typedef enum CheckStatus { } CheckStatus; CheckStatus check_block(AstBlock* block); -CheckStatus check_statement_chain(AstNode* start); -CheckStatus check_statement(AstNode* stmt); +CheckStatus check_statement_chain(AstNode** start); +CheckStatus check_statement(AstNode** pstmt); CheckStatus check_return(AstReturn* retnode); CheckStatus check_if(AstIfWhile* ifnode); CheckStatus check_while(AstIfWhile* whilenode); @@ -36,6 +36,7 @@ CheckStatus check_address_of(AstAddressOf* aof); CheckStatus check_dereference(AstDereference* deref); CheckStatus check_array_access(AstArrayAccess* expr); CheckStatus check_field_access(AstFieldAccess** pfield); +CheckStatus check_method_call(AstBinaryOp** mcall); CheckStatus check_size_of(AstSizeOf* so); CheckStatus check_align_of(AstAlignOf* ao); CheckStatus check_global(AstGlobal* global); @@ -115,7 +116,7 @@ CheckStatus check_return(AstReturn* retnode) { } CheckStatus check_if(AstIfWhile* ifnode) { - if (ifnode->assignment != NULL) CHECK(statement, (AstNode *) ifnode->assignment); + if (ifnode->assignment != NULL) CHECK(statement, (AstNode **) &ifnode->assignment); CHECK(expression, &ifnode->cond); @@ -124,14 +125,14 @@ CheckStatus check_if(AstIfWhile* ifnode) { return Check_Error; } - if (ifnode->true_stmt) CHECK(statement, (AstNode *) ifnode->true_stmt); - if (ifnode->false_stmt) CHECK(statement, (AstNode *) ifnode->false_stmt); + if (ifnode->true_stmt) CHECK(statement, (AstNode **) &ifnode->true_stmt); + if (ifnode->false_stmt) CHECK(statement, (AstNode **) &ifnode->false_stmt); return Check_Success; } CheckStatus check_while(AstIfWhile* whilenode) { - if (whilenode->assignment != NULL) CHECK(statement, (AstNode *) whilenode->assignment); + if (whilenode->assignment != NULL) CHECK(statement, (AstNode **) &whilenode->assignment); CHECK(expression, &whilenode->cond); @@ -140,8 +141,8 @@ CheckStatus check_while(AstIfWhile* whilenode) { return Check_Error; } - if (whilenode->true_stmt) CHECK(statement, (AstNode *) whilenode->true_stmt); - if (whilenode->false_stmt) CHECK(statement, (AstNode *) whilenode->false_stmt); + if (whilenode->true_stmt) CHECK(statement, (AstNode **) &whilenode->true_stmt); + if (whilenode->false_stmt) CHECK(statement, (AstNode **) &whilenode->false_stmt); return Check_Success; } @@ -240,7 +241,7 @@ static b32 add_case_to_switch_statement(AstSwitch* switchnode, u64 case_value, A } CheckStatus check_switch(AstSwitch* switchnode) { - if (switchnode->assignment != NULL) CHECK(statement, (AstNode *) switchnode->assignment); + if (switchnode->assignment != NULL) CHECK(statement, (AstNode **) &switchnode->assignment); CHECK(expression, &switchnode->expr); resolve_expression_type(switchnode->expr); @@ -1255,11 +1256,9 @@ CheckStatus check_array_access(AstArrayAccess* aa) { || aa->addr->type->kind == Type_Kind_DynArray || aa->addr->type->kind == Type_Kind_VarArgs) { // If we are accessing on a slice or a dynamic array, implicitly add a field access for the data member - StructMember smem; type_lookup_member(aa->addr->type, "data", &smem); - AstFieldAccess* fa = make_field_access(context.ast_alloc, aa->addr, "data"); fa->type = smem.type; fa->offset = smem.offset; @@ -1314,23 +1313,18 @@ CheckStatus check_field_access(AstFieldAccess** pfield) { } if (!type_lookup_member(field->expr->type, field->field, &smem)) { - AstStructType* struct_node = (AstStructType *) field->expr->type->ast_type; - assert(struct_node); - assert(struct_node->kind == Ast_Kind_Struct_Type); - - AstNode* n = symbol_raw_resolve(struct_node->scope, field->field); + AstType* type_node = field->expr->type->ast_type; + AstNode* n = try_symbol_raw_resolve_from_node((AstNode *) type_node, field->field); if (n) { *pfield = (AstFieldAccess *) n; return Check_Success; - - } else { - onyx_report_error(field->token->pos, - "Field '%s' does not exists on '%s'.", - field->field, - node_get_type_name(field->expr)); - - return Check_Error; } + + onyx_report_error(field->token->pos, + "Field '%s' does not exists on '%s'.", + field->field, + node_get_type_name(field->expr)); + return Check_Error; } field->offset = smem.offset; @@ -1340,6 +1334,33 @@ CheckStatus check_field_access(AstFieldAccess** pfield) { return Check_Success; } +CheckStatus check_method_call(AstBinaryOp** mcall) { + CHECK(expression, &(*mcall)->left); + + AstTyped* implicit_argument = (*mcall)->left; + + // Implicitly take the address of the value if it is not already a pointer type. + // This could be weird to think about semantically so some testing with real code + // would be good. - brendanfh 2020/02/05 + if (implicit_argument->type->kind != Type_Kind_Pointer) + implicit_argument = (AstTyped *) make_address_of(context.ast_alloc, implicit_argument); + + implicit_argument = (AstTyped *) make_argument(context.ast_alloc, implicit_argument); + + // Symbol resolution should have ensured that this is call node. + AstCall* call_node = (AstCall *) (*mcall)->right; + assert(call_node->kind == Ast_Kind_Call); + + bh_arr_insertn(call_node->args.values, 0, 1); + call_node->args.values[0] = implicit_argument; + + CHECK(call, call_node); + call_node->next = (*mcall)->next; + + *mcall = (AstBinaryOp *) call_node; + return Check_Success; +} + CheckStatus check_size_of(AstSizeOf* so) { fill_in_array_count(so->so_ast_type); @@ -1410,6 +1431,7 @@ CheckStatus check_expression(AstTyped** pexpr) { case Ast_Kind_Slice: case Ast_Kind_Array_Access: retval = check_array_access((AstArrayAccess *) expr); break; case Ast_Kind_Field_Access: retval = check_field_access((AstFieldAccess **) pexpr); break; + case Ast_Kind_Method_Call: retval = check_method_call((AstBinaryOp **) pexpr); break; case Ast_Kind_Size_Of: retval = check_size_of((AstSizeOf *) expr); break; case Ast_Kind_Align_Of: retval = check_align_of((AstAlignOf *) expr); break; case Ast_Kind_Range_Literal: retval = check_range_literal((AstRangeLiteral **) pexpr); break; @@ -1495,7 +1517,9 @@ CheckStatus check_global(AstGlobal* global) { return Check_Success; } -CheckStatus check_statement(AstNode* stmt) { +CheckStatus check_statement(AstNode** pstmt) { + AstNode* stmt = *pstmt; + switch (stmt->kind) { case Ast_Kind_Jump: return Check_Success; @@ -1505,29 +1529,29 @@ CheckStatus check_statement(AstNode* stmt) { case Ast_Kind_For: return check_for((AstFor *) stmt); case Ast_Kind_Switch: return check_switch((AstSwitch *) stmt); case Ast_Kind_Block: return check_block((AstBlock *) stmt); - case Ast_Kind_Defer: return check_statement(((AstDefer *) stmt)->stmt); + case Ast_Kind_Defer: return check_statement(&((AstDefer *) stmt)->stmt); case Ast_Kind_Binary_Op: stmt->flags |= Ast_Flag_Expr_Ignored; - return check_binaryop((AstBinaryOp **) &stmt, 1); + return check_binaryop((AstBinaryOp **) pstmt, 1); default: stmt->flags |= Ast_Flag_Expr_Ignored; - return check_expression((AstTyped **) &stmt); + return check_expression((AstTyped **) pstmt); } } -CheckStatus check_statement_chain(AstNode* start) { - while (start) { +CheckStatus check_statement_chain(AstNode** start) { + while (*start) { CHECK(statement, start); - start = start->next; + start = &(*start)->next; } return Check_Success; } CheckStatus check_block(AstBlock* block) { - CHECK(statement_chain, block->body); + CHECK(statement_chain, &block->body); bh_arr_each(AstTyped *, value, block->allocate_exprs) { fill_in_type(*value); diff --git a/src/onyxsymres.c b/src/onyxsymres.c index 126135cc..dd3053ac 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -315,7 +315,6 @@ static void symres_pipe(AstBinaryOp** pipe) { *pipe = (AstBinaryOp *) call_node; } -// nocheckin // CLEANUP: This is an experimental feature and might be removed in the future. // I noticed a common pattern when writing in Onyx is something that looks like this: // @@ -336,20 +335,10 @@ static void symres_method_call(AstBinaryOp** mcall) { symres_expression(&(*mcall)->left); if ((*mcall)->left == NULL) return; - bh_arr_insertn(call_node->args.values, 0, 1); - - AstTyped* implicit_pointer = (AstTyped *) make_address_of(context.ast_alloc, (*mcall)->left); - call_node->args.values[0] = (AstTyped *) make_argument(context.ast_alloc, implicit_pointer); - AstFieldAccess* implicit_field_access = make_field_access(context.ast_alloc, (*mcall)->left, NULL); implicit_field_access->token = call_node->callee->token; call_node->callee = (AstTyped *) implicit_field_access; symres_expression((AstTyped **) &call_node); - - call_node->next = (*mcall)->next; - - // NOTE: Not a BinaryOp node - *mcall = (AstBinaryOp *) call_node; } static void symres_unaryop(AstUnaryOp** unaryop) { diff --git a/src/onyxutils.c b/src/onyxutils.c index 9c6bd506..b1d99c21 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -140,13 +140,20 @@ AstNode* symbol_resolve(Scope* start_scope, OnyxToken* tkn) { return res; } -AstNode* try_symbol_resolve_from_node(AstNode* node, OnyxToken* token) { +AstNode* try_symbol_raw_resolve_from_node(AstNode* node, char* symbol) { + // CLEANUP: So many checks for null.... + if (!node) return NULL; + if (node->kind == Ast_Kind_Type_Raw_Alias) node = (AstNode *) ((AstTypeRawAlias *) node)->to->ast_type; + if (!node) return NULL; + if (node->kind == Ast_Kind_Type_Alias) node = (AstNode *) ((AstTypeAlias *) node)->to; + if (!node) return NULL; + // A single pointer can be dereferenced to lookup symbols in struct. if (node->kind == Ast_Kind_Pointer_Type) node = (AstNode *) ((AstPointerType *) node)->elem; @@ -156,28 +163,36 @@ AstNode* try_symbol_resolve_from_node(AstNode* node, OnyxToken* token) { switch (node->kind) { case Ast_Kind_Package: { AstPackage* package = (AstPackage *) node; - return symbol_resolve(package->package->scope, token); + return symbol_raw_resolve(package->package->scope, symbol); } case Ast_Kind_Enum_Type: { AstEnumType* etype = (AstEnumType *) node; - return symbol_resolve(etype->scope, token); + return symbol_raw_resolve(etype->scope, symbol); } case Ast_Kind_Struct_Type: { AstStructType* stype = (AstStructType *) node; - return symbol_resolve(stype->scope, token); + return symbol_raw_resolve(stype->scope, symbol); } case Ast_Kind_Poly_Struct_Type: { AstStructType* stype = ((AstPolyStructType *) node)->base_struct; - return symbol_resolve(stype->scope, token); + return symbol_raw_resolve(stype->scope, symbol); } } return NULL; } +AstNode* try_symbol_resolve_from_node(AstNode* node, OnyxToken* token) { + token_toggle_end(token); + AstNode* result = try_symbol_raw_resolve_from_node(node, token->text); + token_toggle_end(token); + + return result; +} + void scope_clear(Scope* scope) { bh_table_clear(scope->symbols); }