summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Maniero <carlos@maniero.me>2023-05-10 16:07:39 -0300
committerCarlos Maniero <carlos@maniero.me>2023-05-10 17:35:03 -0300
commit75639fbf01bd6ae1212521b6cf822025eb8b598d (patch)
tree49709154c437cfbc01568f1e0c9abc8574fd3a54
parent2cf0bcb409f3a1fd298b664103d57c945c6349f5 (diff)
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 <carlos@maniero.me>
-rw-r--r--src/ast.c42
-rw-r--r--src/ast.h16
-rw-r--r--src/ast_pretty_printer.c13
-rw-r--r--src/gas_assembly_generator.c20
-rw-r--r--src/gas_assembly_generator.h3
-rw-r--r--src/main.c14
-rw-r--r--src/parser.c37
-rw-r--r--src/parser.h3
-rw-r--r--test/parser_test.c12
9 files changed, 140 insertions, 20 deletions
diff --git a/src/ast.c b/src/ast.c
index 5790c05..47d658d 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -44,6 +44,9 @@ void
ast_node_destroy(ast_node_t *node)
{
switch (node->kind) {
+ case AST_NAMESPACE:
+ ast_node_destroy_vector(node->data.ns.nodes);
+ break;
case AST_FUNCTION_DECLARATION:
ast_node_destroy(node->data.function.body);
break;
@@ -108,6 +111,24 @@ ast_node_new_function_declaration(string_view_t function_name, type_t return_typ
}
ast_node_t *
+ast_node_new_namespace(vector_t *nodes)
+{
+ ast_node_t *node = ast_node_new();
+
+ *node = (ast_node_t){
+ .kind = AST_NAMESPACE,
+ .result_type = TYPE_VOID,
+ .data = {
+ .ns = {
+ .nodes = nodes,
+ }
+ },
+ };
+
+ return node;
+}
+
+ast_node_t *
ast_node_new_block(vector_t *body)
{
ast_node_t *node = ast_node_new();
@@ -254,6 +275,27 @@ ast_node_new_variable(ast_identifier_t *identifier, type_t result_type)
return node;
}
+ast_node_t *
+ast_node_ns_get_function_node_by_sv(ast_node_t *ns, string_view_t name)
+{
+ assert(ns->kind == AST_NAMESPACE);
+
+ for (size_t i = 0; i < ns->data.ns.nodes->size; i++) {
+ ast_node_t *node = vector_at(ns->data.ns.nodes, i);
+
+ if (node->kind == AST_FUNCTION_DECLARATION && string_view_eq(node->data.function.identifier.name, name)) {
+ return node;
+ }
+ }
+ return NULL;
+}
+
+ast_node_t *
+ast_node_ns_get_function_node_by_name(ast_node_t *ns, char *function_name)
+{
+ return ast_node_ns_get_function_node_by_sv(ns, string_view_from_str(function_name));
+}
+
char *
ast_type_to_str(type_t type)
{
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;
@@ -164,6 +171,9 @@ 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,
ast_node_t *right,
@@ -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 */
diff --git a/src/ast_pretty_printer.c b/src/ast_pretty_printer.c
index b14bf34..f5fcf70 100644
--- a/src/ast_pretty_printer.c
+++ b/src/ast_pretty_printer.c
@@ -65,6 +65,19 @@ ast_pretty_printer_print_ast(ast_pretty_printer_t *printer, ast_node_t *ast)
assert(ast);
switch (ast->kind) {
+ case AST_NAMESPACE:
+ ast_pretty_printer_printf(printer, "Namespace\n");
+ ast_pretty_printer_add_indentation(printer);
+ {
+ for (size_t i = 0; i < ast->data.ns.nodes->size; ++i) {
+ if (i + 1 >= ast->data.ns.nodes->size) {
+ ast_pretty_printer_set_lst_children(printer);
+ }
+ ast_pretty_printer_print_ast(printer, vector_at(ast->data.ns.nodes, i));
+ }
+ ast_pretty_printer_rm_indentation(printer);
+ }
+ break;
case AST_IF_STMT: {
ast_if_stmt_t if_stmt = ast->data.if_stmt;
ast_pretty_printer_printf(printer, "IfStmt\n");
diff --git a/src/gas_assembly_generator.c b/src/gas_assembly_generator.c
index 413fbb0..4326b27 100644
--- a/src/gas_assembly_generator.c
+++ b/src/gas_assembly_generator.c
@@ -147,6 +147,9 @@ gas_assembly_generator_compile(gas_assembly_generator_t *gen, ast_node_t *ast)
gen->latest_evaluation.kind = EVALUATION_RESULT_VOID;
switch (ast->kind) {
+ case AST_NAMESPACE:
+ gas_assembly_generator_compile_ns(gen, &ast->data.ns);
+ break;
case AST_BINARY_OPERATION:
gas_assembly_generator_binary_operation(gen, &ast->data.binary_operation);
break;
@@ -179,6 +182,14 @@ gas_assembly_generator_compile(gas_assembly_generator_t *gen, ast_node_t *ast)
}
}
+void
+gas_assembly_generator_compile_ns(gas_assembly_generator_t *gen, ast_namespace_t *ns)
+{
+ for (size_t i = 0; i < ns->nodes->size; i++) {
+ gas_assembly_generator_compile(gen, vector_at(ns->nodes, i));
+ }
+}
+
static void
gas_assembly_generator_compile_function(gas_assembly_generator_t *gen, ast_function_declaration_t *func)
{
@@ -201,12 +212,9 @@ gas_assembly_generator_compile_function(gas_assembly_generator_t *gen, ast_funct
}
void
-gas_assembly_generator_compile_linux_main(gas_assembly_generator_t *gen, ast_node_t *func)
+gas_assembly_generator_compile_linux_main(gas_assembly_generator_t *gen, ast_node_t *ns)
{
- assert(func);
- assert(func->kind == AST_FUNCTION_DECLARATION);
-
- if (!string_view_eq(func->data.function.identifier.name, string_view_from_str("main"))) {
+ if (ast_node_ns_get_function_node_by_name(ns, "main") == NULL) {
fprintf(stderr, "[ERROR]: no main function has been defined!\n");
exit(EXIT_FAILURE);
}
@@ -214,7 +222,7 @@ gas_assembly_generator_compile_linux_main(gas_assembly_generator_t *gen, ast_nod
fprintf(gen->stream, ".global _start\n");
fprintf(gen->stream, ".text\n");
- gas_assembly_generator_compile(gen, func);
+ gas_assembly_generator_compile(gen, ns);
fprintf(gen->stream, "_start:\n");
fprintf(gen->stream, " call main\n");
diff --git a/src/gas_assembly_generator.h b/src/gas_assembly_generator.h
index 18ffb7f..26aa87b 100644
--- a/src/gas_assembly_generator.h
+++ b/src/gas_assembly_generator.h
@@ -60,6 +60,9 @@ void
gas_assembly_generator_compile(gas_assembly_generator_t *gen, ast_node_t *ast);
void
+gas_assembly_generator_compile_ns(gas_assembly_generator_t *gen, ast_namespace_t *ns);
+
+void
gas_assembly_generator_compile_linux_main(gas_assembly_generator_t *gen, ast_node_t *func);
#endif /* GAS_ASSEMBLY_GENERATOR_H */
diff --git a/src/main.c b/src/main.c
index 780499c..ca6ed9b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -27,11 +27,11 @@
#include "string_view.h"
static void
-generate_gas_x86_64_linux(ast_node_t *func)
+generate_gas_x86_64_linux(ast_node_t *ns)
{
gas_assembly_generator_t gen;
gas_assembly_generator_init(&gen, stdout);
- gas_assembly_generator_compile_linux_main(&gen, func);
+ gas_assembly_generator_compile_linux_main(&gen, ns);
}
static void
@@ -89,20 +89,20 @@ main(int argc, char **argv)
parser_t parser;
parser_init(&parser, &lexer, scope);
- ast_node_t *func = parser_parse_function_declaration(&parser);
+ ast_node_t *ns = parser_parse_ns(&parser);
- if (func == NULL) {
+ if (ns == NULL) {
parser_print_errors(&parser);
return EXIT_FAILURE;
}
if (should_dump_ast) {
- pretty_print_ast(func);
+ pretty_print_ast(ns);
} else {
- generate_gas_x86_64_linux(func);
+ generate_gas_x86_64_linux(ns);
}
scope_destroy(scope);
- ast_node_destroy(func);
+ ast_node_destroy(ns);
return EXIT_SUCCESS;
}
diff --git a/src/parser.c b/src/parser.c
index e3f157f..b94087f 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -571,6 +571,22 @@ is_next_statement_return(parser_t *parser)
}
static bool
+is_next_function_declaration(parser_t *parser)
+{
+ token_t token;
+ lexer_peek_next_token(parser->lexer, &token);
+ return token.kind == TOKEN_KEYWORD_FN;
+}
+
+static bool
+is_next_token_eof(parser_t *parser)
+{
+ token_t token;
+ lexer_peek_next_token(parser->lexer, &token);
+ return token.kind == TOKEN_EOF;
+}
+
+static bool
is_block_end(parser_t *parser)
{
token_t token;
@@ -746,3 +762,24 @@ parser_parse_function_declaration(parser_t *parser)
return node;
}
+
+ast_node_t *
+parser_parse_ns(parser_t *parser)
+{
+ vector_t *nodes = vector_new();
+
+ while (!is_next_token_eof(parser)) {
+ if (is_next_function_declaration(parser)) {
+ ast_node_t *node = parser_parse_function_declaration(parser);
+
+ if (node == NULL) {
+ ast_node_destroy_vector(nodes);
+ return NULL;
+ }
+
+ vector_push_back(nodes, node);
+ }
+ }
+
+ return ast_node_new_namespace(nodes);
+}
diff --git a/src/parser.h b/src/parser.h
index ef5dff5..7bebee7 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -46,4 +46,7 @@ parser_parse_function_declaration(parser_t *parser);
ast_node_t *
parser_parse_expression(parser_t *parser);
+ast_node_t *
+parser_parse_ns(parser_t *parser);
+
#endif /* PARSER_H */
diff --git a/test/parser_test.c b/test/parser_test.c
index 8565dc8..78e2e23 100644
--- a/test/parser_test.c
+++ b/test/parser_test.c
@@ -64,17 +64,15 @@ test_parse_function(const MunitParameter params[], void *user_data_or_fixture)
lexer_t lexer;
scope_t *scope = scope_new();
- make_lexer_from_static_src(&lexer, "fn main(): i32 { \nreturn 42;\n }");
+ make_lexer_from_static_src(&lexer, "fn add(): i32 { return 2; } fn main(): i32 { \nreturn 42;\n }");
parser_init(&parser, &lexer, scope);
- ast_node_t *ast_function = parser_parse_function_declaration(&parser);
+ ast_node_t *ast_ns = parser_parse_ns(&parser);
- assert_not_null(ast_function);
+ assert_not_null(ast_ns);
- char actual[5];
+ ast_node_t *ast_function = ast_node_ns_get_function_node_by_name(ast_ns, "main");
- string_view_to_str(&ast_function->data.function.identifier.name, actual);
- assert_string_equal("main", actual);
- assert_int(AST_FUNCTION_DECLARATION, ==, ast_function->kind);
+ assert_not_null(ast_function);
ast_node_t *ast_return = vector_at(ast_function->data.function.body->data.block.body, 0);