15 | 15 |
*/
|
16 | 16 |
#include "../../config.h"
|
17 | 17 |
#include "cypher-parser.h"
|
|
18 |
#include <assert.h>
|
18 | 19 |
#include <errno.h>
|
19 | 20 |
#include <getopt.h>
|
20 | 21 |
#include <libgen.h>
|
|
29 | 30 |
#define COLORIZE_OPT 1004
|
30 | 31 |
#define ONLY_STATEMENTS_OPT 1005
|
31 | 32 |
#define OUTPUT_WIDTH_OPT 1006
|
32 | |
#define VERSION_OPT 1007
|
|
33 |
#define STREAM_OPT 1007
|
|
34 |
#define VERSION_OPT 1008
|
33 | 35 |
|
34 | 36 |
static struct option longopts[] =
|
35 | 37 |
{ { "ast", no_argument, NULL, 'a' },
|
|
37 | 39 |
{ "help", no_argument, NULL, 'h' },
|
38 | 40 |
{ "only-statements", no_argument, NULL, ONLY_STATEMENTS_OPT },
|
39 | 41 |
{ "output-width", required_argument, NULL, OUTPUT_WIDTH_OPT },
|
|
42 |
{ "stream", no_argument, NULL, STREAM_OPT },
|
40 | 43 |
{ "version", no_argument, NULL, VERSION_OPT },
|
41 | 44 |
{ NULL, 0, NULL, 0 } };
|
42 | 45 |
|
|
51 | 54 |
" --help, -h Output this usage information.\n"
|
52 | 55 |
" --only-statements Only parse statements (and not client commands).\n"
|
53 | 56 |
" --output-width <n> Attempt to limit output to the specified width.\n"
|
|
57 |
" --stream Output each statement as it is read, rather than parsing\n"
|
|
58 |
" the entire input first (note: will result in inconsistent\n"
|
|
59 |
" formatting of AST dumps).\n"
|
54 | 60 |
" --version Output the version of cypher-lint and libcypher-parser\n"
|
55 | 61 |
"\n",
|
56 | 62 |
prog_name);
|
|
64 | 70 |
bool dump_ast;
|
65 | 71 |
bool colorize_output;
|
66 | 72 |
bool colorize_errors;
|
|
73 |
bool stream;
|
67 | 74 |
};
|
68 | 75 |
|
69 | 76 |
|
70 | 77 |
static int process(FILE *stream, struct lint_config *config);
|
|
78 |
static int process_streamed(FILE *stream, struct lint_config *config,
|
|
79 |
cypher_parser_config_t *cp_config,
|
|
80 |
const struct cypher_parser_colorization *error_colorization,
|
|
81 |
const struct cypher_parser_colorization *output_colorization);
|
|
82 |
static int process_all(FILE *stream, struct lint_config *config,
|
|
83 |
cypher_parser_config_t *cp_config,
|
|
84 |
const struct cypher_parser_colorization *error_colorization,
|
|
85 |
const struct cypher_parser_colorization *output_colorization);
|
71 | 86 |
static int parse_callback(void *data, cypher_parse_segment_t *segment);
|
|
87 |
static void print_error(const cypher_parse_error_t *error,
|
|
88 |
const struct cypher_parser_colorization *colorization);
|
72 | 89 |
|
73 | 90 |
|
74 | 91 |
int main(int argc, char *argv[])
|
|
118 | 135 |
break;
|
119 | 136 |
case OUTPUT_WIDTH_OPT:
|
120 | 137 |
config.width = atoi(optarg);
|
|
138 |
break;
|
|
139 |
case STREAM_OPT:
|
|
140 |
config.stream = true;
|
121 | 141 |
break;
|
122 | 142 |
case VERSION_OPT:
|
123 | 143 |
fprintf(stdout, "neo4j-lint: %s\n", PACKAGE_VERSION);
|
|
145 | 165 |
}
|
146 | 166 |
|
147 | 167 |
|
|
168 |
int process(FILE *stream, struct lint_config *config)
|
|
169 |
{
|
|
170 |
cypher_parser_config_t *cp_config = cypher_parser_new_config();
|
|
171 |
if (cp_config == NULL)
|
|
172 |
{
|
|
173 |
return -1;
|
|
174 |
}
|
|
175 |
|
|
176 |
const struct cypher_parser_colorization *error_colorization =
|
|
177 |
cypher_parser_no_colorization;
|
|
178 |
if (config->colorize_errors)
|
|
179 |
{
|
|
180 |
error_colorization = cypher_parser_ansi_colorization;
|
|
181 |
cypher_parser_config_set_error_colorization(cp_config,
|
|
182 |
error_colorization);
|
|
183 |
}
|
|
184 |
|
|
185 |
const struct cypher_parser_colorization *output_colorization =
|
|
186 |
config->colorize_output? cypher_parser_ansi_colorization : NULL;
|
|
187 |
|
|
188 |
int err = (config->stream)?
|
|
189 |
process_streamed(stream, config, cp_config,
|
|
190 |
error_colorization, output_colorization) :
|
|
191 |
process_all(stream, config, cp_config,
|
|
192 |
error_colorization, output_colorization);
|
|
193 |
|
|
194 |
int errsv = errno;
|
|
195 |
cypher_parser_config_free(cp_config);
|
|
196 |
errno = errsv;
|
|
197 |
return err;
|
|
198 |
}
|
|
199 |
|
|
200 |
|
148 | 201 |
struct parse_callback_data
|
149 | 202 |
{
|
150 | 203 |
struct lint_config *config;
|
|
154 | 207 |
};
|
155 | 208 |
|
156 | 209 |
|
157 | |
int process(FILE *stream, struct lint_config *config)
|
158 | |
{
|
159 | |
cypher_parser_config_t *cp_config = cypher_parser_new_config();
|
160 | |
if (cp_config == NULL)
|
161 | |
{
|
162 | |
return -1;
|
163 | |
}
|
164 | |
|
165 | |
const struct cypher_parser_colorization *error_colorization =
|
166 | |
cypher_parser_no_colorization;
|
167 | |
if (config->colorize_errors)
|
168 | |
{
|
169 | |
error_colorization = cypher_parser_ansi_colorization;
|
170 | |
cypher_parser_config_set_error_colorization(cp_config,
|
171 | |
error_colorization);
|
172 | |
}
|
173 | |
|
174 | |
const struct cypher_parser_colorization *output_colorization =
|
175 | |
config->colorize_output? cypher_parser_ansi_colorization : NULL;
|
176 | |
|
177 | |
|
|
210 |
int process_streamed(FILE *stream, struct lint_config *config,
|
|
211 |
cypher_parser_config_t *cp_config,
|
|
212 |
const struct cypher_parser_colorization *error_colorization,
|
|
213 |
const struct cypher_parser_colorization *output_colorization)
|
|
214 |
{
|
178 | 215 |
struct parse_callback_data callback_data =
|
179 | 216 |
{ .config = config,
|
180 | 217 |
.error_colorization = error_colorization,
|
|
182 | 219 |
.nerrors = 0
|
183 | 220 |
};
|
184 | 221 |
|
185 | |
int result = -1;
|
186 | 222 |
if (cypher_fparse_each(stream, parse_callback, &callback_data, NULL,
|
187 | 223 |
cp_config, config->flags))
|
188 | 224 |
{
|
189 | 225 |
perror("cypher_fparse_each");
|
|
226 |
return -1;
|
|
227 |
}
|
|
228 |
|
|
229 |
return (callback_data.nerrors == 0)? 0 : 1;
|
|
230 |
}
|
|
231 |
|
|
232 |
|
|
233 |
int parse_callback(void *data, cypher_parse_segment_t *segment)
|
|
234 |
{
|
|
235 |
struct parse_callback_data *cbdata =
|
|
236 |
(struct parse_callback_data *)data;
|
|
237 |
struct lint_config *config = cbdata->config;
|
|
238 |
|
|
239 |
unsigned int i = 0;
|
|
240 |
const cypher_parse_error_t *error;
|
|
241 |
for (; (error = cypher_parse_segment_get_error(segment, i)) != NULL; ++i)
|
|
242 |
{
|
|
243 |
print_error(error, cbdata->error_colorization);
|
|
244 |
}
|
|
245 |
|
|
246 |
cbdata->nerrors += i;
|
|
247 |
|
|
248 |
if (config->dump_ast && cypher_parse_segment_fprint_ast(segment, stdout,
|
|
249 |
config->width, cbdata->output_colorization, 0) < 0)
|
|
250 |
{
|
|
251 |
perror("cypher_parse_segment_fprint_ast");
|
|
252 |
return -1;
|
|
253 |
}
|
|
254 |
|
|
255 |
return 0;
|
|
256 |
}
|
|
257 |
|
|
258 |
|
|
259 |
int process_all(FILE *stream, struct lint_config *config,
|
|
260 |
cypher_parser_config_t *cp_config,
|
|
261 |
const struct cypher_parser_colorization *error_colorization,
|
|
262 |
const struct cypher_parser_colorization *output_colorization)
|
|
263 |
{
|
|
264 |
cypher_parse_result_t *result =
|
|
265 |
cypher_fparse(stream, NULL, cp_config, config->flags);
|
|
266 |
if (result == NULL)
|
|
267 |
{
|
|
268 |
perror("cypher_fparse");
|
|
269 |
return -1;
|
|
270 |
}
|
|
271 |
|
|
272 |
int err = -1;
|
|
273 |
|
|
274 |
unsigned int i = 0;
|
|
275 |
const cypher_parse_error_t *error;
|
|
276 |
for (; (error = cypher_parse_result_get_error(result, i)) != NULL; ++i)
|
|
277 |
{
|
|
278 |
print_error(error, error_colorization);
|
|
279 |
}
|
|
280 |
|
|
281 |
if (config->dump_ast && cypher_parse_result_fprint_ast(result, stdout,
|
|
282 |
config->width, output_colorization, 0) < 0)
|
|
283 |
{
|
|
284 |
perror("cypher_parse_result_fprint_ast");
|
190 | 285 |
goto cleanup;
|
191 | 286 |
}
|
192 | 287 |
|
193 | |
result = (callback_data.nerrors > 0)? 0 : 1;
|
|
288 |
err = (cypher_parse_result_nerrors(result) == 0)? 0 : 1;
|
194 | 289 |
|
195 | 290 |
int errsv;
|
196 | 291 |
cleanup:
|
197 | 292 |
errsv = errno;
|
198 | |
cypher_parser_config_free(cp_config);
|
|
293 |
cypher_parse_result_free(result);
|
199 | 294 |
errno = errsv;
|
200 | |
return result;
|
201 | |
}
|
202 | |
|
203 | |
|
204 | |
int parse_callback(void *data, cypher_parse_segment_t *segment)
|
205 | |
{
|
206 | |
struct parse_callback_data *callback_data =
|
207 | |
(struct parse_callback_data *)data;
|
208 | |
struct lint_config *config = callback_data->config;
|
209 | |
|
210 | |
unsigned int i = 0;
|
211 | |
const cypher_parse_error_t *error;
|
212 | |
for (; (error = cypher_parse_segment_get_error(segment, i)) != NULL; ++i)
|
213 | |
{
|
214 | |
struct cypher_input_position pos =
|
215 | |
cypher_parse_error_position(error);
|
216 | |
const char *msg = cypher_parse_error_message(error);
|
217 | |
const char *context = cypher_parse_error_context(error);
|
218 | |
unsigned int offset = cypher_parse_error_context_offset(error);
|
219 | |
fprintf(stderr, "%s %s(line %u, column %u, offset %zu)%s%s\n", msg,
|
220 | |
callback_data->error_colorization->error_message[0],
|
221 | |
pos.line, pos.column, pos.offset,
|
222 | |
callback_data->error_colorization->error_message[1],
|
223 | |
(context == NULL)? "" : ":");
|
224 | |
fprintf(stderr, "%s\n%*.*s^\n", context, offset, offset, " ");
|
225 | |
}
|
226 | |
|
227 | |
callback_data->nerrors += i;
|
228 | |
|
229 | |
if (config->dump_ast && cypher_parse_segment_fprint_ast(segment, stdout,
|
230 | |
config->width, callback_data->output_colorization, 0) < 0)
|
231 | |
{
|
232 | |
perror("cypher_parse_result_fprint");
|
233 | |
return -1;
|
234 | |
}
|
235 | |
|
236 | |
return 0;
|
237 | |
}
|
|
295 |
return err;
|
|
296 |
}
|
|
297 |
|
|
298 |
|
|
299 |
void print_error(const cypher_parse_error_t *error,
|
|
300 |
const struct cypher_parser_colorization *colorization)
|
|
301 |
{
|
|
302 |
struct cypher_input_position pos = cypher_parse_error_position(error);
|
|
303 |
const char *msg = cypher_parse_error_message(error);
|
|
304 |
const char *context = cypher_parse_error_context(error);
|
|
305 |
unsigned int offset = cypher_parse_error_context_offset(error);
|
|
306 |
fprintf(stderr, "%s %s(line %u, column %u, offset %zu)%s%s\n", msg,
|
|
307 |
colorization->error_message[0], pos.line, pos.column, pos.offset,
|
|
308 |
colorization->error_message[1], (context == NULL)? "" : ":");
|
|
309 |
fprintf(stderr, "%s\n%*.*s^\n", context, offset, offset, " ");
|
|
310 |
}
|