aboutsummaryrefslogtreecommitdiff
path: root/repl.c
blob: fd204b018539131856e5ed693472bc888a085dc5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/*
 * repl.c: test REPL
 *
 * Copyright (c) 2017, Přemysl Janouch <p.janouch@gmail.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "ell.c"
#include <readline/readline.h>
#include <readline/history.h>

static void
run (struct context *ctx, struct item *program) {
	struct item *result = NULL;
	(void) execute_block (ctx, program, NULL, &result);
	item_free_list (program);

	const char *failure = ctx->error;
	if (ctx->memory_failure)
		failure = "memory allocation failure";
	if (failure) {
		printf ("\x1b[31m%s: %s\x1b[0m\n", "runtime error", failure);
		free (ctx->error);
		ctx->error = NULL;
		ctx->memory_failure = false;
	} else {
		print_item_list (result);
		putchar ('\n');
		item_free_list (result);
	}
}

static int
init_readline (void) {
	rl_variable_bind ("blink-matching-paren", "on");
	rl_bind_key (TAB, rl_named_function ("possible-completions"));
	return 0;
}

struct context ctx;

static char **
complete (const char *text, int start, int end) {
	(void) start;
	(void) end;

	// Don't iterate over filenames and stuff
	rl_attempted_completion_over = true;

	static char *buf[128];
	size_t n = 1, len = strlen (text);
	for (struct item *item = ctx.globals; item; item = item->next)
		if (n < 127 && !strncmp (item->head->value, text, len))
			buf[n++] = format ("%s", item->head->value);
	for (struct native_fn *iter = ctx.native; iter; iter = iter->next)
		if (n < 127 && !strncmp (iter->name, text, len))
			buf[n++] = format ("%s", iter->name);
	if (n < 2)
		return NULL;

	// This never actually completes anything, just shows the options,
	// we'd have to figure out the longest common prefix
	buf[0] = format ("%s", text);

	buf[n++] = NULL;
	char **copy = malloc (sizeof *buf * n);
	memcpy (copy, buf, sizeof *buf * n);
	return copy;
}

int
main (int argc, char *argv[]) {
	(void) argc;

	context_init (&ctx);
	if (!init_runtime_library (&ctx))
		printf ("%s\n", "runtime library initialization failed");

	using_history ();
	const char *slash = strrchr (argv[0], '/');
	rl_readline_name = slash ? ++slash : argv[0];
	rl_startup_hook = init_readline;
	rl_attempted_completion_function = complete;

	char *line;
	while ((line = readline ("> "))) {
		struct parser parser;
		parser_init (&parser, line, strlen (line));
		add_history (line);

		const char *e = NULL;
		struct item *program = parser_run (&parser, &e);
		free (line);
		if (e)
			printf ("\x1b[31m%s: %s\x1b[0m\n", "parse error", e);
		else
			run (&ctx, program);
		parser_free (&parser);
	}

	putchar ('\n');
	context_free (&ctx);
	return 0;
}