aboutsummaryrefslogtreecommitdiff
path: root/repl.c
blob: 400d7a115ea8e8e759aa1dd116d93f1123d37627 (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
/*
 * repl.c: test REPL
 *
 * Copyright (c) 2017, Přemysl Eric Janouch <p@janouch.name>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted.
 *
 * 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/history.h>
#include <readline/readline.h>

static void
run (struct ell *ell, struct ell_v *program) {
	struct ell_v *result = NULL;
	(void) ell_eval_block (ell, program, NULL, &result);
	ell_free_seq (program);

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

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

static struct ell ell;

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 ell_v *v = ell.globals; v; v = v->next)
		if (n < 127 && !strncmp (v->head->string, text, len))
			buf[n++] = ell_format ("%s", v->head->string);
	for (struct ell_native_fn *iter = ell.native; iter; iter = iter->next)
		if (n < 127 && !strncmp (iter->name, text, len))
			buf[n++] = ell_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] = ell_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;

	ell = ell_make ();
	if (!ell_std_initialize (&ell))
		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 ell_parser p = ell_parser_make (line, strlen (line));
		add_history (line);

		const char *e = NULL;
		struct ell_v *program = ell_parser_run (&p, &e);
		free (line);
		if (e)
			printf ("\x1b[31m%s: %s\x1b[0m\n", "parse error", e);
		else
			run (&ell, program);
		ell_parser_free (&p);
	}

	putchar ('\n');
	ell_free (&ell);
	return 0;
}