Skip to content

Commit

Permalink
feat: add ast_to_json() function
Browse files Browse the repository at this point in the history
  • Loading branch information
Silva97 committed Jan 20, 2025
1 parent 88f1681 commit 6d9f148
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 0 deletions.
36 changes: 36 additions & 0 deletions src/globals.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <stdlib.h>

#include "types/ast.h"
#include "types/keywords.h"
#include "types/operators.h"
#include "version.h"
Expand Down Expand Up @@ -31,3 +32,38 @@ const char* mya_operators[] = {
[OP_XOR] = "^",
NULL,
};

const char* mya_token_types[] = {
[TK_CLOSE_BRACES] = "close_braces",
// clang-format hates me.
[TK_CLOSE_BRACKET] = "close_bracket",
[TK_CLOSE_PARENS] = "close_parentheses",
[TK_COLON] = "colon",
[TK_COMMA] = "comma",
[TK_EQUAL] = "equal",
[TK_IDENTIFIER] = "identifier",
[TK_KEYWORD] = "keyword",
[TK_NUMBER] = "number",
[TK_OPEN_BRACES] = "open_braces",
[TK_OPEN_BRACKET] = "open_bracket",
[TK_OPEN_PARENS] = "open_parentheses",
[TK_OPERATOR] = "operator",
[TK_SEMICOLON] = "semicolon",
[TK_STRING] = "string",
NULL,
};

const char* mya_node_types[] = {
[NT_ARG_LIST] = "argument_list",
// clang-format hates me.
[NT_BITFIELD_BODY] = "bitfield_body",
[NT_EXPRESSION] = "expression",
[NT_IDENTIFIER] = "identifier",
[NT_INST_BODY] = "inst_body",
[NT_ROOT] = "root",
[NT_SIZE_SPEC] = "size_spec",
[NT_STATEMENT] = "statement",
[NT_STRING] = "string",
[NT_TYPE] = "type_name",
NULL,
};
11 changes: 11 additions & 0 deletions src/include/ast.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include <stdio.h>

#include "types/ast.h"

/**
Expand Down Expand Up @@ -54,3 +56,12 @@ ast_insert_children(ast_node_t* parent, ast_node_t* child);
*/
void
ast_copy(ast_node_t* destiny, ast_node_t* source);

/**
* Reads the AST and converts it to JSON, writting on the given file stream.
*
* @param root The root of the AST.
* @param file The file where to write the JSON.
*/
void
ast_to_json(ast_node_t* root, FILE* file);
2 changes: 2 additions & 0 deletions src/include/types/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,5 @@ typedef struct ast_node
unsigned int children_count;
unsigned int _children_length;
} ast_node_t;

extern const char* mya_node_types[];
2 changes: 2 additions & 0 deletions src/include/types/token.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ typedef struct token
long long int value; ///< Integer value of the token on TK_NUMBER tokens.
dstring_t lexeme; ///< Lexeme of the token.
} token_t;

extern const char* mya_token_types[];
61 changes: 61 additions & 0 deletions src/types/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
#include <string.h>

#include "ast.h"
#include "types/token.h"

static void
_ast_to_json_aux(ast_node_t* root, FILE* file, int level);

static void
_print_at_level(FILE* file, int level, char* text);

static void
_ast_ensure_children_size(ast_node_t* node);
Expand Down Expand Up @@ -59,6 +66,60 @@ ast_copy(ast_node_t* destiny, ast_node_t* source)
memcpy(destiny, source, sizeof(ast_node_t));
}

void
ast_to_json(ast_node_t* root, FILE* file)
{
_ast_to_json_aux(root, file, 0);
fputc('\n', file);
}

#define _JSON_PRINT_FIELD(level, name, fmt, ...) \
_print_at_level(file, level, "\"" name "\": "); \
fprintf(file, fmt, __VA_ARGS__);

static void
_ast_to_json_aux(ast_node_t* root, FILE* file, int level)
{
_print_at_level(file, level, "{\n");

_JSON_PRINT_FIELD(level + 1, "type", "\"%s\",\n", mya_node_types[root->type]);

if (root->token != NULL) {
_JSON_PRINT_FIELD(level + 1, "token", "%s", "{\n");
_JSON_PRINT_FIELD(level + 2, "lexeme", "\"%s\",\n", root->token->lexeme.data);
_JSON_PRINT_FIELD(level + 2, "type", "\"%s\",\n", mya_token_types[root->token->type]);
_JSON_PRINT_FIELD(level + 2, "line", "%d,\n", root->token->line);
_JSON_PRINT_FIELD(level + 2, "column", "%d,\n", root->token->column);
_JSON_PRINT_FIELD(level + 2, "value", "%lld\n", root->token->value);
_print_at_level(file, level + 1, "},\n");
}

if (root->children_count == 0) {
_JSON_PRINT_FIELD(level + 1, "children", "%s", "[]\n");
} else {
_JSON_PRINT_FIELD(level + 1, "children", "%s", "[\n");
for (int i = 0; i < root->children_count; i++) {
_ast_to_json_aux(&root->children[i], file, level + 2);

fputs((i < root->children_count - 1 ? ",\n" : "\n"), file);
}
_print_at_level(file, level + 1, "]\n");
}

_print_at_level(file, level, "}");
}

static void
_print_at_level(FILE* file, int level, char* text)
{
if (level <= 0) {
fputs(text, file);
return;
}

fprintf(file, "%*c%s", level * 2, ' ', text);
}

static void
_ast_ensure_children_size(ast_node_t* node)
{
Expand Down

0 comments on commit 6d9f148

Please sign in to comment.