#include "gravity_symboltable.h"
#include "gravity_semacheck1.h"
#include "gravity_compiler.h"
#include "gravity_visitor.h"
#define REPORT_ERROR(node,...) {report_error(self, (gnode_t *)node, __VA_ARGS__); return;}
#define DECLARE_SYMTABLE symboltable_t *symtable = (symboltable_t *)self->data
#define SAVE_SYMTABLE symboltable_t *saved = symtable
#define CREATE_SYMTABLE INC_IDENT; SAVE_SYMTABLE; self->data = (void *)symboltable_create(false);
#define RESTORE_SYMTABLE DEC_IDENT; node->symtable = ((symboltable_t *)self->data); self->data = (void *)saved
#if GRAVITY_SYMTABLE_DEBUG
static int ident =0;
#define INC_IDENT ++ident
#define DEC_IDENT --ident
#else
#define INC_IDENT
#define DEC_IDENT
#endif
static void report_error (gvisitor_t *self, gnode_t *node, const char *format, ...) {
++self->nerr;
void *data = (self->delegate) ? ((gravity_delegate_t *)self->delegate)->xdata : NULL;
gravity_error_callback error_fn = (self->delegate) ? ((gravity_delegate_t *)self->delegate)->error_callback : NULL;
char buffer[1024];
va_list arg;
if (format) {
va_start (arg, format);
vsnprintf(buffer, sizeof(buffer), format, arg);
va_end (arg);
}
error_desc_t error_desc = {
.code = 0,
.lineno = node->token.lineno,
.colno = node->token.colno,
.fileid = node->token.fileid,
.offset = node->token.position
};
if (error_fn) error_fn(GRAVITY_ERROR_SEMANTIC, buffer, error_desc, data);
else printf("%s\n", buffer);
}
static void visit_list_stmt (gvisitor_t *self, gnode_compound_stmt_t *node) {
DECLARE_SYMTABLE;
node->symtable = symtable;
gnode_array_each(node->stmts, {visit(val);});
}
static void visit_function_decl (gvisitor_t *self, gnode_function_decl_t *node) {
DECLARE_SYMTABLE;
DEBUG_SYMTABLE("function: %s", node->identifier);
if (!symboltable_insert(symtable, node->identifier, (void *)node))
REPORT_ERROR(node, "Identifier %s redeclared.", node->identifier);
}
static void visit_variable_decl (gvisitor_t *self, gnode_variable_decl_t *node) {
DECLARE_SYMTABLE;
gnode_array_each(node->decls, {
gnode_var_t *p = (gnode_var_t *)val;
DEBUG_SYMTABLE("variable: %s", p->identifier);
if (!symboltable_insert(symtable, p->identifier, (void *)p))
REPORT_ERROR(p, "Identifier %s redeclared.", p->identifier);
});
}
static void visit_enum_decl (gvisitor_t *self, gnode_enum_decl_t *node) {
DECLARE_SYMTABLE;
DEBUG_SYMTABLE("enum: %s", node->identifier);
if (!symboltable_insert(symtable, node->identifier, (void *)node))
REPORT_ERROR(node, "Identifier %s redeclared.", node->identifier);
}
static void visit_class_decl (gvisitor_t *self, gnode_class_decl_t *node) {
DECLARE_SYMTABLE;
DEBUG_SYMTABLE("class: %s", node->identifier);
if (!symboltable_insert(symtable, node->identifier, (void *)node))
REPORT_ERROR(node, "Identifier %s redeclared.", node->identifier);
CREATE_SYMTABLE;
gnode_array_each(node->decls, {
visit(val);
});
RESTORE_SYMTABLE;
}
static void visit_module_decl (gvisitor_t *self, gnode_module_decl_t *node) {
DECLARE_SYMTABLE;
DEBUG_SYMTABLE("module: %s", node->identifier);
if (!symboltable_insert(symtable, node->identifier, (void *)node))
REPORT_ERROR(node, "Identifier %s redeclared.", node->identifier);
CREATE_SYMTABLE;
gnode_array_each(node->decls, {
visit(val);
});
RESTORE_SYMTABLE;
}
bool gravity_semacheck1 (gnode_t *node, gravity_delegate_t *delegate) {
symboltable_t *context = symboltable_create(false);
gvisitor_t visitor = {
.nerr = 0,
.data = (void *)context,
.delegate = (void *)delegate,
.visit_list_stmt = visit_list_stmt,
.visit_compound_stmt = NULL,
.visit_label_stmt = NULL,
.visit_flow_stmt = NULL,
.visit_loop_stmt = NULL,
.visit_jump_stmt = NULL,
.visit_empty_stmt = NULL,
.visit_function_decl = visit_function_decl,
.visit_variable_decl = visit_variable_decl,
.visit_enum_decl = visit_enum_decl,
.visit_class_decl = visit_class_decl,
.visit_module_decl = visit_module_decl,
.visit_binary_expr = NULL,
.visit_unary_expr = NULL,
.visit_file_expr = NULL,
.visit_literal_expr = NULL,
.visit_identifier_expr = NULL,
.visit_keyword_expr = NULL,
.visit_list_expr = NULL,
.visit_postfix_expr = NULL,
};
DEBUG_SYMTABLE("=== SYMBOL TABLE ===");
gvisit(&visitor, node);
DEBUG_SYMTABLE("====================\n");
return (visitor.nerr == 0);
}