Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
epidemian
GitHub Repository: epidemian/gravity
Path: blob/master/src/compiler/gravity_semacheck1.c
1214 views
1
//
2
// gravity_semacheck1.c
3
// gravity
4
//
5
// Created by Marco Bambini on 08/10/14.
6
// Copyright (c) 2014 CreoLabs. All rights reserved.
7
//
8
9
#include "gravity_symboltable.h"
10
#include "gravity_semacheck1.h"
11
#include "gravity_compiler.h"
12
#include "gravity_visitor.h"
13
14
#define REPORT_ERROR(node,...) {report_error(self, (gnode_t *)node, __VA_ARGS__); return;}
15
16
#define DECLARE_SYMTABLE symboltable_t *symtable = (symboltable_t *)self->data
17
#define SAVE_SYMTABLE symboltable_t *saved = symtable
18
#define CREATE_SYMTABLE INC_IDENT; SAVE_SYMTABLE; self->data = (void *)symboltable_create(false);
19
#define RESTORE_SYMTABLE DEC_IDENT; node->symtable = ((symboltable_t *)self->data); self->data = (void *)saved
20
21
#if GRAVITY_SYMTABLE_DEBUG
22
static int ident =0;
23
#define INC_IDENT ++ident
24
#define DEC_IDENT --ident
25
#else
26
#define INC_IDENT
27
#define DEC_IDENT
28
#endif
29
30
// MARK: -
31
32
static void report_error (gvisitor_t *self, gnode_t *node, const char *format, ...) {
33
// increment internal error counter
34
++self->nerr;
35
36
// get error callback (if any)
37
void *data = (self->delegate) ? ((gravity_delegate_t *)self->delegate)->xdata : NULL;
38
gravity_error_callback error_fn = (self->delegate) ? ((gravity_delegate_t *)self->delegate)->error_callback : NULL;
39
40
// build error message
41
char buffer[1024];
42
va_list arg;
43
if (format) {
44
va_start (arg, format);
45
vsnprintf(buffer, sizeof(buffer), format, arg);
46
va_end (arg);
47
}
48
49
// setup error struct
50
error_desc_t error_desc = {
51
.code = 0,
52
.lineno = node->token.lineno,
53
.colno = node->token.colno,
54
.fileid = node->token.fileid,
55
.offset = node->token.position
56
};
57
58
// finally call error callback
59
if (error_fn) error_fn(GRAVITY_ERROR_SEMANTIC, buffer, error_desc, data);
60
else printf("%s\n", buffer);
61
}
62
63
// MARK: - Declarations -
64
65
static void visit_list_stmt (gvisitor_t *self, gnode_compound_stmt_t *node) {
66
DECLARE_SYMTABLE;
67
68
node->symtable = symtable; // GLOBALS
69
gnode_array_each(node->stmts, {visit(val);});
70
}
71
72
static void visit_function_decl (gvisitor_t *self, gnode_function_decl_t *node) {
73
DECLARE_SYMTABLE;
74
75
DEBUG_SYMTABLE("function: %s", node->identifier);
76
77
// function identifier
78
if (!symboltable_insert(symtable, node->identifier, (void *)node))
79
REPORT_ERROR(node, "Identifier %s redeclared.", node->identifier);
80
81
// we are just interested in non-local declarations so don't further scan function node
82
// node->symtable is NULL here and it will be created in semacheck2
83
}
84
85
static void visit_variable_decl (gvisitor_t *self, gnode_variable_decl_t *node) {
86
DECLARE_SYMTABLE;
87
88
gnode_array_each(node->decls, {
89
gnode_var_t *p = (gnode_var_t *)val;
90
DEBUG_SYMTABLE("variable: %s", p->identifier);
91
if (!symboltable_insert(symtable, p->identifier, (void *)p))
92
REPORT_ERROR(p, "Identifier %s redeclared.", p->identifier);
93
});
94
}
95
96
static void visit_enum_decl (gvisitor_t *self, gnode_enum_decl_t *node) {
97
DECLARE_SYMTABLE;
98
99
DEBUG_SYMTABLE("enum: %s", node->identifier);
100
101
// check enum identifier uniqueness in current symbol table
102
if (!symboltable_insert(symtable, node->identifier, (void *)node))
103
REPORT_ERROR(node, "Identifier %s redeclared.", node->identifier);
104
}
105
106
static void visit_class_decl (gvisitor_t *self, gnode_class_decl_t *node) {
107
DECLARE_SYMTABLE;
108
109
DEBUG_SYMTABLE("class: %s", node->identifier);
110
111
// class identifier
112
if (!symboltable_insert(symtable, node->identifier, (void *)node))
113
REPORT_ERROR(node, "Identifier %s redeclared.", node->identifier);
114
115
CREATE_SYMTABLE;
116
gnode_array_each(node->decls, {
117
visit(val);
118
});
119
RESTORE_SYMTABLE;
120
}
121
122
static void visit_module_decl (gvisitor_t *self, gnode_module_decl_t *node) {
123
DECLARE_SYMTABLE;
124
125
DEBUG_SYMTABLE("module: %s", node->identifier);
126
127
// module identifier
128
if (!symboltable_insert(symtable, node->identifier, (void *)node))
129
REPORT_ERROR(node, "Identifier %s redeclared.", node->identifier);
130
131
CREATE_SYMTABLE;
132
gnode_array_each(node->decls, {
133
visit(val);
134
});
135
RESTORE_SYMTABLE;
136
}
137
138
// MARK: -
139
140
bool gravity_semacheck1 (gnode_t *node, gravity_delegate_t *delegate) {
141
symboltable_t *context = symboltable_create(false);
142
143
gvisitor_t visitor = {
144
.nerr = 0, // used to store number of found errors
145
.data = (void *)context, // used to store a pointer to the symbol table
146
.delegate = (void *)delegate, // compiler delegate to report errors
147
148
// STATEMENTS: 7
149
.visit_list_stmt = visit_list_stmt,
150
.visit_compound_stmt = NULL,
151
.visit_label_stmt = NULL,
152
.visit_flow_stmt = NULL,
153
.visit_loop_stmt = NULL,
154
.visit_jump_stmt = NULL,
155
.visit_empty_stmt = NULL,
156
157
// DECLARATIONS: 5
158
.visit_function_decl = visit_function_decl,
159
.visit_variable_decl = visit_variable_decl,
160
.visit_enum_decl = visit_enum_decl,
161
.visit_class_decl = visit_class_decl,
162
.visit_module_decl = visit_module_decl,
163
164
// EXPRESSIONS: 8
165
.visit_binary_expr = NULL,
166
.visit_unary_expr = NULL,
167
.visit_file_expr = NULL,
168
.visit_literal_expr = NULL,
169
.visit_identifier_expr = NULL,
170
.visit_keyword_expr = NULL,
171
.visit_list_expr = NULL,
172
.visit_postfix_expr = NULL,
173
};
174
175
DEBUG_SYMTABLE("=== SYMBOL TABLE ===");
176
gvisit(&visitor, node);
177
DEBUG_SYMTABLE("====================\n");
178
179
return (visitor.nerr == 0);
180
}
181
182