From 75639fbf01bd6ae1212521b6cf822025eb8b598d Mon Sep 17 00:00:00 2001 From: Carlos Maniero Date: Wed, 10 May 2023 16:07:39 -0300 Subject: namespaces: Add a namespace structure that represents a file We have been always parsing a single function. Since we want to have multiple functions in a near future, this patch introduces an namespace that represents an entire file. To ensure a function is defined inside a namespace, a helper function was created. Today our ast_node structure is highly exposed, and this is something that Johnny and I have been discussed. So then, this is a first step to try to protected the code generation from our ast tree. Signed-off-by: Carlos Maniero --- src/ast.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src/ast.h') diff --git a/src/ast.h b/src/ast.h index b2c565c..7d2d2f1 100644 --- a/src/ast.h +++ b/src/ast.h @@ -29,6 +29,11 @@ typedef enum typedef struct ast_node_t ast_node_t; +typedef struct ast_namespace_t +{ + vector_t *nodes; +} ast_namespace_t; + typedef struct ast_block_t { vector_t *body; @@ -119,6 +124,7 @@ typedef struct ast_if_stmt_t typedef enum { + AST_NAMESPACE, AST_BINARY_OPERATION, AST_BLOCK, AST_FUNCTION_DECLARATION, @@ -133,6 +139,7 @@ typedef enum typedef union { + ast_namespace_t ns; ast_binary_operation_t binary_operation; ast_function_declaration_t function; ast_literal_t literal; @@ -163,6 +170,9 @@ ast_node_destroy_vector(vector_t *vector); void ast_node_destroy(ast_node_t *node); +ast_node_t * +ast_node_new_namespace(vector_t *nodes); + ast_node_t * ast_node_new_binary_operation(ast_binary_operation_kind_t kind, ast_node_t *left, @@ -196,4 +206,10 @@ ast_node_new_variable_assignment(ast_identifier_t *identifier, ast_node_t *expre ast_node_t * ast_node_new_if_stmt(ast_node_t *condition, ast_node_t *body); +ast_node_t * +ast_node_ns_get_function_node_by_sv(ast_node_t *ns, string_view_t name); + +ast_node_t * +ast_node_ns_get_function_node_by_name(ast_node_t *ns, char *function_name); + #endif /* AST_H */ -- cgit v1.2.3 From 3129b741064c2b4f2c6c2408bd42cc83f7341ea8 Mon Sep 17 00:00:00 2001 From: Carlos Maniero Date: Wed, 10 May 2023 16:53:05 -0300 Subject: gas: Generate function call This is an initial commit that enables function calls. At this point only functions with no parameters is going to work. Signed-off-by: Carlos Maniero --- src/ast.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src/ast.h') diff --git a/src/ast.h b/src/ast.h index 7d2d2f1..315de1e 100644 --- a/src/ast.h +++ b/src/ast.h @@ -54,6 +54,11 @@ typedef struct ast_variable_t ast_identifier_t *identifier; } ast_variable_t; +typedef struct ast_function_call_t +{ + ast_identifier_t *identifier; +} ast_function_call_t; + typedef struct ast_function_declaration_t { ast_identifier_t identifier; @@ -128,6 +133,7 @@ typedef enum AST_BINARY_OPERATION, AST_BLOCK, AST_FUNCTION_DECLARATION, + AST_FUNCTION_CALL, AST_LITERAL, AST_RETURN_STMT, AST_IF_STMT, @@ -142,6 +148,7 @@ typedef union ast_namespace_t ns; ast_binary_operation_t binary_operation; ast_function_declaration_t function; + ast_function_call_t function_call; ast_literal_t literal; ast_block_t block; ast_if_stmt_t if_stmt; @@ -182,6 +189,9 @@ ast_node_new_binary_operation(ast_binary_operation_kind_t kind, ast_node_t * ast_node_new_function_declaration(string_view_t function_name, type_t return_type, ast_node_t *body); +ast_node_t * +ast_node_new_function_call(ast_identifier_t *identifier, type_t result_type); + ast_node_t * ast_node_new_return_stmt(ast_node_t *argument); @@ -212,4 +222,10 @@ ast_node_ns_get_function_node_by_sv(ast_node_t *ns, string_view_t name); ast_node_t * ast_node_ns_get_function_node_by_name(ast_node_t *ns, char *function_name); +bool +ast_node_is_variable_declaration(ast_node_t *node); + +bool +ast_node_is_function_declaration(ast_node_t *node); + #endif /* AST_H */ -- cgit v1.2.3 From 5042a4ffc1363d6f0f99a3afd79f76cf2da738d6 Mon Sep 17 00:00:00 2001 From: Carlos Maniero Date: Wed, 10 May 2023 22:24:14 -0300 Subject: gas: implement function calls For now function calls are following the C's calling convention, which means they are using the following registers to pass functions' arguments: rdi, rsi, rdx, rcx, r8, r9 If a function has more then 6 parameters, the compilation will fail. To enable function with more than 6 parameters we will need to save the extra arguments on stack. Naming: parameters: function parameters are the variables a function receives. arguments: Arguments are the values passed to a function when calling it. Calling mechanism: When a function is called, all the expressions passed as argument are evaluated, after the evaluation, the result is stored on the register that represents its argument position, the first argument will be stored on rdi, the second on rsi and so on. Receiving mechanism: When a function starts, the first thing it does is store all the registers onto the stack. So rdi will be stored on -8(rbp), rsi on -16(rbp) and so on. And, a ref_entry is created making the relationship parameter-stack_offset. Signed-off-by: Carlos Maniero --- src/ast.h | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) (limited to 'src/ast.h') diff --git a/src/ast.h b/src/ast.h index 315de1e..9e0e514 100644 --- a/src/ast.h +++ b/src/ast.h @@ -57,12 +57,25 @@ typedef struct ast_variable_t typedef struct ast_function_call_t { ast_identifier_t *identifier; + vector_t *arguments; } ast_function_call_t; -typedef struct ast_function_declaration_t +typedef struct ast_function_parameter_t +{ + ast_identifier_t identifier; + type_t type; +} ast_function_parameter_t; + +typedef struct ast_function_prototype_t { ast_identifier_t identifier; type_t return_type; + vector_t *parameters; +} ast_function_prototype_t; + +typedef struct ast_function_declaration_t +{ + ast_function_prototype_t prototype; ast_node_t *body; } ast_function_declaration_t; @@ -133,6 +146,7 @@ typedef enum AST_BINARY_OPERATION, AST_BLOCK, AST_FUNCTION_DECLARATION, + AST_FUNCTION_PARAMETER, AST_FUNCTION_CALL, AST_LITERAL, AST_RETURN_STMT, @@ -148,6 +162,7 @@ typedef union ast_namespace_t ns; ast_binary_operation_t binary_operation; ast_function_declaration_t function; + ast_function_parameter_t function_parameter; ast_function_call_t function_call; ast_literal_t literal; ast_block_t block; @@ -187,10 +202,16 @@ ast_node_new_binary_operation(ast_binary_operation_kind_t kind, type_t result_type); ast_node_t * -ast_node_new_function_declaration(string_view_t function_name, type_t return_type, ast_node_t *body); +ast_node_new_function_declaration(string_view_t function_name, + type_t return_type, + vector_t *parameters, + ast_node_t *body); + +ast_node_t * +ast_node_new_function_parameter(string_view_t name, type_t type); ast_node_t * -ast_node_new_function_call(ast_identifier_t *identifier, type_t result_type); +ast_node_new_function_call(ast_identifier_t *identifier, type_t result_type, vector_t *arguments); ast_node_t * ast_node_new_return_stmt(ast_node_t *argument); @@ -228,4 +249,10 @@ ast_node_is_variable_declaration(ast_node_t *node); bool ast_node_is_function_declaration(ast_node_t *node); +ast_identifier_t * +ast_node_function_declaration_identifier(ast_node_t *node); + +string_view_t +ast_node_function_declaration_name(ast_node_t *node); + #endif /* AST_H */ -- cgit v1.2.3 From ea7f65fe1250be8f49edcaaedd3410aed1401648 Mon Sep 17 00:00:00 2001 From: Carlos Maniero Date: Thu, 11 May 2023 15:00:10 -0300 Subject: gas: implement recursion and late evaluation Until now the below code was not valid for pipac. fn main(): i32 { return fib(13); } fn fib(n: i32): i32 { if n <= 1 { return n; } return fib(n - 1) + fib(n - 2); } Pipa's parser was adding a function to scope after they were fully parsed which means that fib's self-reference would not work. Also, functions were required to follow the be called in the order they are declared for the same scope reason so, the main function was required to be defined after fib. And how it is working now? When a TOKEN_NAME is not found in the scope, instead of returning an error, an unknown token is created as placeholder. The parser stores the node reference and the token it was trying to parse. During type checks, if the parser detects an unknown node, instead of returning an error, it stores in that node what was the expected type. After the NS is fully parsed a reevaluation is made on those unknown nodes by setting the lexer back on the node's token position and parsing the TOKEN_NAME again. Ps: There is a typo on the unknown token. It will be addressed in another commit since this issue was not introduced by this change. Signed-off-by: Carlos Maniero --- src/ast.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'src/ast.h') diff --git a/src/ast.h b/src/ast.h index 9e0e514..42f02ac 100644 --- a/src/ast.h +++ b/src/ast.h @@ -16,6 +16,7 @@ */ #ifndef AST_H #define AST_H +#include "lexer.h" #include "string_view.h" #include "vector.h" #include @@ -140,6 +141,12 @@ typedef struct ast_if_stmt_t ast_node_t *body; } ast_if_stmt_t; +typedef struct ast_unkown_token_t +{ + type_t expected_type; + token_t reference_token; +} ast_unkown_token_t; + typedef enum { AST_NAMESPACE, @@ -151,10 +158,10 @@ typedef enum AST_LITERAL, AST_RETURN_STMT, AST_IF_STMT, - AST_UNKOWN_NODE, AST_VARIABLE_DECLARATION, AST_VARIABLE_ASSIGNMENT, - AST_VARIABLE + AST_VARIABLE, + AST_UNKOWN_NODE } ast_node_kind_t; typedef union @@ -171,6 +178,7 @@ typedef union ast_variable_declaration_t variable_declaration; ast_variable_assignment_t variable_assignment; ast_variable_t variable; + ast_unkown_token_t unknown; } ast_node_data_t; typedef struct ast_node_t -- cgit v1.2.3