added experimental 'method call' syntax
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 2 Feb 2021 20:28:03 +0000 (14:28 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 2 Feb 2021 20:28:03 +0000 (14:28 -0600)
bin/onyx
core/js/webgl.onyx
include/onyxastnodes.h
onyx.exe
src/onyx.c
src/onyxastnodes.c
src/onyxparser.c
src/onyxsymres.c

index c9f7b5c2bf113b6cb37c90aac60695c8beba9551..705f3739f1cc961268f959665e7de9738678cef6 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index 2167761c907685a903dfda129ecfad7b22fe0e9a..02a22b6205aed779c35d25e9f5421c860be5c51f 100644 (file)
@@ -738,7 +738,7 @@ blendFuncSeparate              :: (srcRGB: GLenum, dstRGB: GLenum, srcAlpha: GLe
 blitFramebuffer                :: (sx0: GLint, sy0: GLint, sx1: GLint, sy1: GLint, dx0: GLint, dy0: GLint, dx1: GLint, dy1: GLint, mask: GLbitfield, filter: GLenum) -> void #foreign "gl" "blitFramebuffer" ---
 bufferDataWithData             :: (target: GLenum, buffer: [] void, usage: GLenum) -> void #foreign "gl" "bufferDataWithData" ---
 bufferDataNoData               :: (target: GLenum, size: GLsizeiptr, usage: GLenum) -> void #foreign "gl" "bufferDataNoData" ---
-bufferData                     :: { bufferDataWithData, bufferDataNoData }
+bufferData                     :: proc { bufferDataWithData, bufferDataNoData }
 bufferSubData                  :: (target: GLenum, offset: GLsizei, data: [] void) -> void #foreign "gl" "bufferSubData" ---
 canvasSize                     :: (width: GLsizei, height: GLsizei) -> void #foreign "gl" "canvasSize" ---
 checkFrameBufferStatus         :: (target: GLenum) -> GLenum #foreign "gl" "checkFrameBufferStatus" ---
index 0617aa7bc5dd777a79cb045e7e9294780e984a0c..5d477b6c4e9848ca9e567697d22231ca5b8386f9 100644 (file)
@@ -146,6 +146,7 @@ typedef enum AstKind {
     Ast_Kind_Slice,
     Ast_Kind_Field_Access,
     Ast_Kind_Pipe,
+    Ast_Kind_Method_Call,
     Ast_Kind_Range_Literal,
     Ast_Kind_Size_Of,
     Ast_Kind_Align_Of,
@@ -263,6 +264,7 @@ typedef enum BinaryOp {
 
     Binary_Op_Pipe            = 33,
     Binary_Op_Range           = 34,
+    Binary_Op_Method_Call     = 35,
 
     Binary_Op_Count
 } BinaryOp;
@@ -1067,6 +1069,7 @@ AstRangeLiteral* make_range_literal(bh_allocator a, AstTyped* low, AstTyped* hig
 AstBinaryOp* make_binary_op(bh_allocator a, BinaryOp operation, AstTyped* left, AstTyped* right);
 AstArgument* make_argument(bh_allocator a, AstTyped* value);
 AstFieldAccess* make_field_access(bh_allocator a, AstTyped* node, char* field);
+AstAddressOf* make_address_of(bh_allocator a, AstTyped* node);
 AstLocal* make_local(bh_allocator a, OnyxToken* token, AstType* type_node);
 AstNode* make_symbol(bh_allocator a, OnyxToken* sym);
 
index eee67d0598f6cefa2ff9d8ff3a73e9124051b222..e0845ccfbabd952be4b177dc452106665b448dcf 100644 (file)
Binary files a/onyx.exe and b/onyx.exe differ
index 0be1e45a0094215078f655ca8dc1e71d2f15eda2..a01a38ae36d9c383e5034a3c4014d9e97d09b533 100644 (file)
@@ -327,7 +327,7 @@ static i32 onyx_compile() {
         entity_heap_remove_top(&context.entities);
 
 #if defined(_BH_LINUX)
-            if (context.options->fun_output) {
+        if (context.options->fun_output) {
             output_dummy_progress_bar();
             
             if (ent.expr->token) {
index 1ea640df011cf2c6c01afee5c4bbd67d15e8974b..9d39772fe979ce5967ea32c13039f1a9000aa4c3 100644 (file)
@@ -64,6 +64,7 @@ static const char* ast_node_names[] = {
     "SLICE",
     "FIELD_ACCESS",
     "PIPE",
+    "METHOD_CALL",
     "RANGE",
     "SIZE OF",
     "ALIGN OF",
@@ -688,6 +689,14 @@ AstFieldAccess* make_field_access(bh_allocator a, AstTyped* node, char* field) {
     return fa;
 }
 
+AstAddressOf* make_address_of(bh_allocator a, AstTyped* node) {
+    AstAddressOf* ao = onyx_ast_node_new(a, sizeof(AstAddressOf), Ast_Kind_Address_Of);
+    if (node->token) ao->token = node->token;
+    ao->expr = node;
+
+    return ao; 
+}
+
 AstLocal* make_local(bh_allocator a, OnyxToken* token, AstType* type_node) {
     AstLocal* local = onyx_ast_node_new(a, sizeof(AstLocal), Ast_Kind_Local);
     local->token = token;
index 9251f6c79d8f27119f3bcf22162521367588e76a..d6fc334aa1d4336dde7a40fcb58c54badafe69f4 100644 (file)
@@ -196,8 +196,7 @@ static b32 parse_possible_directive(OnyxParser* parser, const char* dir) {
 }
 
 static b32 parse_possible_struct_literal(OnyxParser* parser, AstTyped* left, AstTyped** ret) {
-    if (parser->curr->type != '.'
-        || peek_token(1)->type != '{') return 0;
+    if (parser->curr->type != '.' || peek_token(1)->type != '{') return 0;
 
     AstStructLiteral* sl = make_node(AstStructLiteral, Ast_Kind_Struct_Literal);
     sl->token = parser->curr;
@@ -596,6 +595,16 @@ static AstTyped* parse_factor(OnyxParser* parser) {
                 break;
             }
 
+            case Token_Type_Right_Arrow: {
+                AstBinaryOp* method_call = make_node(AstBinaryOp, Ast_Kind_Method_Call);
+                method_call->token = expect_token(parser, Token_Type_Right_Arrow);  
+                method_call->left = retval;
+                method_call->right = parse_factor(parser);
+
+                retval = (AstTyped *) method_call;
+                break;
+            }
+
             default: goto factor_parsed;
         }
     }
@@ -2073,7 +2082,8 @@ static AstBinding* parse_top_level_binding(OnyxParser* parser, OnyxToken* symbol
     AstTyped* node = parse_top_level_expression(parser);
     if (parser->hit_unexpected_token || node == NULL)
         return NULL;
-
+    
+    // CLEANUP
     if (node->kind == Ast_Kind_Function) {
         AstFunction* func = (AstFunction *) node;
 
@@ -2132,7 +2142,8 @@ static AstNode* parse_top_level_statement(OnyxParser* parser) {
     else if (parse_possible_directive(parser, "private_file")) {
         private_kind = Ast_Flag_Private_File;
     }
-
+    
+    // CLEANUP
     switch ((u16) parser->curr->type) {
         case Token_Type_Keyword_Use: {
             AstNode* use_node = parse_use_stmt(parser);
@@ -2145,9 +2156,7 @@ static AstNode* parse_top_level_statement(OnyxParser* parser) {
             return NULL;
 
         case Token_Type_Symbol: {
-            OnyxToken* symbol = parser->curr;
-            consume_token(parser);
-
+            OnyxToken* symbol = expect_token(parser, Token_Type_Symbol);
             expect_token(parser, ':');
 
             if (parser->curr->type == ':') {
@@ -2156,27 +2165,26 @@ static AstNode* parse_top_level_statement(OnyxParser* parser) {
                 if (binding != NULL) binding->node->flags |= private_kind;
 
                 return (AstNode *) binding;
+            }
+            
+            AstMemRes* memres = make_node(AstMemRes, Ast_Kind_Memres);
+            memres->token = symbol;
 
-            } else {
-                AstMemRes* memres = make_node(AstMemRes, Ast_Kind_Memres);
-                memres->token = symbol;
-
-                if (parser->curr->type != '=')
-                    memres->type_node = parse_type(parser);
-
-                if (consume_token_if_next(parser, '='))
-                    memres->initial_value = parse_expression(parser, 1);
-
-                memres->flags |= private_kind;
-                
-                ENTITY_SUBMIT(memres);
-                
-                AstBinding* binding = make_node(AstBinding, Ast_Kind_Binding);
-                binding->token = symbol;
-                binding->node = (AstNode *) memres;
+            if (parser->curr->type != '=')
+                memres->type_node = parse_type(parser);
+            
+            if (consume_token_if_next(parser, '='))
+                memres->initial_value = parse_expression(parser, 1);
+            
+            memres->flags |= private_kind;
+            
+            ENTITY_SUBMIT(memres);
+            
+            AstBinding* binding = make_node(AstBinding, Ast_Kind_Binding);
+            binding->token = symbol;
+            binding->node = (AstNode *) memres;
 
-                return (AstNode *) binding;
-            }
+            return (AstNode *) binding;
         }
 
         case '#': {
@@ -2238,7 +2246,8 @@ static AstPackage* parse_package_name(OnyxParser* parser) {
         package_node->package = package;
         return package_node;
     }
-
+    
+    // CLEANUP
     char package_name[1024]; // CLEANUP: This could overflow, if someone decides to be dumb
                              // with their package names  - brendanfh   2020/12/06
     package_name[0] = 0;
index 2a88efe6b8d39def649d0d2be38d2ea75accf81c..0e663545925a92e2526ce2ef6e49034440e11c1f 100644 (file)
@@ -352,6 +352,43 @@ 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:
+//
+//     foo.member_function(^foo, ...)
+//
+// I decided it would be worth adding a bit of syntactic sugar for such as call. I
+// decided to use the '->' operator for this purpose. The snippet below is the exact
+// same as the snippet above (after the nodes have been processed by the function below)
+//
+//     foo->member_function(...)
+static void symres_method_call(AstBinaryOp** mcall) {
+    AstCall* call_node = (AstCall *) (*mcall)->right;
+    if (call_node->kind != Ast_Kind_Call) {
+        onyx_report_error((*mcall)->token->pos, "'->' expected procedure call on right side.");
+        return;
+    }
+
+    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) {
     if ((*unaryop)->operation == Unary_Op_Cast) {
         (*unaryop)->type_node = symres_type((*unaryop)->type_node);
@@ -415,6 +452,7 @@ static void symres_expression(AstTyped** expr) {
         case Ast_Kind_Dereference:  symres_expression(&((AstDereference *)(*expr))->expr); break;
         case Ast_Kind_Field_Access: symres_field_access((AstFieldAccess **) expr); break;
         case Ast_Kind_Pipe:         symres_pipe((AstBinaryOp **) expr); break;
+        case Ast_Kind_Method_Call:  symres_method_call((AstBinaryOp **) expr); break;
         case Ast_Kind_Size_Of:      symres_size_of((AstSizeOf *)*expr); break;
         case Ast_Kind_Align_Of:     symres_align_of((AstAlignOf *)*expr); break;