From 0afc1d869a0328d40f51506a4c2e2dd63e2c8498 Mon Sep 17 00:00:00 2001
From: omicron <omicron.me@protonmail.com>
Date: Mon, 7 Apr 2025 10:49:57 +0200
Subject: [PATCH] Add .import and .export directive to the grammar and parser

---
 doc/parser_grammar.txt  |  6 +++++-
 src/ast.c               |  8 ++++++++
 src/ast.h               |  4 ++++
 src/parser/parser.c     | 18 +++++++++++++++++-
 src/parser/primitives.c | 16 ++++++++++++++++
 src/parser/primitives.h |  2 ++
 6 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/doc/parser_grammar.txt b/doc/parser_grammar.txt
index e7e9315..65ace6f 100644
--- a/doc/parser_grammar.txt
+++ b/doc/parser_grammar.txt
@@ -3,10 +3,14 @@
 
 <label> ::= <identifier> <colon>
 
-<directive> ::= <dot> <section_directive>
+<directive> ::= <dot> (<section_directive> | <export_directive> | <import_directive> )
 
 <section_directive> ::= "section" <identifier>
 
+<export_directive> ::= "export" <identifier>
+
+<import_directive> ::= "import" <identifier>
+
 <instruction> ::= <identifier> <operands>
 
 <operands> ::= <operand> ( <comma> <operand> )*
diff --git a/src/ast.c b/src/ast.c
index 88caf60..740ed40 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -123,6 +123,10 @@ const char *ast_node_id_to_cstr(node_id_t id) {
         return "NODE_PLUS_OR_MINUS";
     case NODE_SECTION_DIRECTIVE:
         return "NODE_SECTION_DIRECTIVE";
+    case NODE_IMPORT_DIRECTIVE:
+        return "NODE_IMPORT_DIRECTIVE";
+    case NODE_EXPORT_DIRECTIVE:
+        return "NODE_EXPORT_DIRECTIVE";
     case NODE_REGISTER:
         return "NODE_REGISTER";
     case NODE_SECTION:
@@ -157,6 +161,10 @@ const char *ast_node_id_to_cstr(node_id_t id) {
         return "NODE_ASTERISK";
     case NODE_DOT:
         return "NODE_DOT";
+    case NODE_IMPORT:
+        return "NODE_IMPORT";
+    case NODE_EXPORT:
+        return "NODE_EXPORT";
     }
     assert(!"Unreachable, weird node id" && id);
     __builtin_unreachable();
diff --git a/src/ast.h b/src/ast.h
index fb6371c..add15ce 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -29,10 +29,14 @@ typedef enum node_id {
     NODE_REGISTER_OFFSET,
     NODE_PLUS_OR_MINUS,
     NODE_SECTION_DIRECTIVE,
+    NODE_IMPORT_DIRECTIVE,
+    NODE_EXPORT_DIRECTIVE,
 
     // Validated primitives
     NODE_REGISTER,
     NODE_SECTION,
+    NODE_IMPORT,
+    NODE_EXPORT,
 
     // Primitive nodes
     NODE_IDENTIFIER,
diff --git a/src/parser/parser.c b/src/parser/parser.c
index 0476666..5880da8 100644
--- a/src/parser/parser.c
+++ b/src/parser/parser.c
@@ -119,8 +119,24 @@ parse_result_t parse_section_directive(tokenlist_entry_t *current) {
     return parse_consecutive(current, NODE_SECTION_DIRECTIVE, parsers);
 }
 
+parse_result_t parse_import_directive(tokenlist_entry_t *current) {
+    parser_t parsers[] = {parse_import, parse_identifier, nullptr};
+    return parse_consecutive(current, NODE_IMPORT_DIRECTIVE, parsers);
+}
+
+parse_result_t parse_export_directive(tokenlist_entry_t *current) {
+    parser_t parsers[] = {parse_export, parse_identifier, nullptr};
+    return parse_consecutive(current, NODE_EXPORT_DIRECTIVE, parsers);
+}
+
+parse_result_t parse_directive_options(tokenlist_entry_t *current) {
+    parser_t parsers[] = {parse_section_directive, parse_import_directive,
+                          parse_export_directive, nullptr};
+    return parse_any(current, parsers);
+}
+
 parse_result_t parse_directive(tokenlist_entry_t *current) {
-    parser_t parsers[] = {parse_dot, parse_section_directive, nullptr};
+    parser_t parsers[] = {parse_dot, parse_directive_options, nullptr};
     return parse_consecutive(current, NODE_DIRECTIVE, parsers);
 }
 
diff --git a/src/parser/primitives.c b/src/parser/primitives.c
index 7e89aa9..ea6c9b2 100644
--- a/src/parser/primitives.c
+++ b/src/parser/primitives.c
@@ -101,3 +101,19 @@ parse_result_t parse_section(tokenlist_entry_t *current) {
     return parse_token(current, TOKEN_IDENTIFIER, NODE_SECTION,
                        is_section_token);
 }
+
+bool is_import_token(lexer_token_t *token) {
+    return strcmp(token->value, "import") == 0;
+}
+
+parse_result_t parse_import(tokenlist_entry_t *current) {
+    return parse_token(current, TOKEN_IDENTIFIER, NODE_IMPORT, is_import_token);
+}
+
+bool is_export_token(lexer_token_t *token) {
+    return strcmp(token->value, "export") == 0;
+}
+
+parse_result_t parse_export(tokenlist_entry_t *current) {
+    return parse_token(current, TOKEN_IDENTIFIER, NODE_EXPORT, is_export_token);
+}
diff --git a/src/parser/primitives.h b/src/parser/primitives.h
index e6df83f..80ab8b6 100644
--- a/src/parser/primitives.h
+++ b/src/parser/primitives.h
@@ -26,5 +26,7 @@ parse_result_t parse_label_reference(tokenlist_entry_t *current);
  */
 parse_result_t parse_register(tokenlist_entry_t *current);
 parse_result_t parse_section(tokenlist_entry_t *current);
+parse_result_t parse_import(tokenlist_entry_t *current);
+parse_result_t parse_export(tokenlist_entry_t *current);
 
 #endif // INCLUDE_PARSER_PRIMITIVES_H_