cherry.c 3.72 KB
Newer Older
1
2
#include <stdio.h>
#include <stdlib.h>
3
#include <getopt.h>
4
#include <readline/readline.h>
5
6
7
#include <gc.h>
#include "cherry/array.h"
#include "cherry/read.h"
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
static void 
print_usage(FILE* out, const char* prog) {
	fprintf(out, "Usage: %s [options] [file]\n");
	fprintf(out, 
		"   -h   --help			     Display this usage information.\n"
		"   -I   --loadpath=[PATH]   Specify loadpath for interpreter.\n"
		"   -M   --main=[method]	 Specify method that is executed automatically.\n");
}


static const cy_byte_t* 
get_text(const char* filename, const char* mode) {
	FILE* file = fopen(filename, mode);
	size_t filesize;

	if(!file)
		return 0;

	fseek(file, 0, SEEK_END);
	filesize = ftell(file);
	rewind(file);

	cy_byte_t* data = GC_MALLOC(filesize * sizeof(cy_byte_t));
	fread(data, sizeof(cy_byte_t), filesize, file);
	fclose(file);

	return data;
}


static void
org_cherry_process_file(const char* filename, const cy_byte_t* method, struct org_cherry_value* arguments)
41
{
42
	const cy_byte_t* src = get_text(filename, "rb");
43

44
45
46
47
48
	if(src == 0) {
		fprintf(stderr, "cherry: couldn't load %s\n", filename);
		exit(EXIT_FAILURE);
	}

49
	struct org_cherry_environment* env = org_cherry_environment();
50
51
	struct org_cherry_context* context = org_cherry_context(src, filename, CY_SUPRESS_COMMENTS);

52
53
	struct org_cherry_value* exp = org_cherry_read(context);

54
	org_cherry_env_push_exception_point(env);
55

56
57
58
59
60
	if(!setjmp(EXCEPTION_JUMP(env))) {
		while(exp != 0) {
			org_cherry_eval(env, exp);
			exp = org_cherry_read(context);
		}
61

62
63
		if(method) {
			struct org_cherry_value* main = org_cherry_list_cons(org_cherry_symbol(method), arguments);
64

65
66
67
68
69
70
71
			org_cherry_eval(env, main);
		}
	} else {
		fprintf(stderr, "EXCEPTION: ");
		org_cherry_print(stderr, HEAD(EXCEPTION_DATA(env)));
		fprintf(stderr, "\n");
		exit(EXIT_FAILURE);
72
73
	}

74
75
	org_cherry_env_pop_exception_point(env);

76
77
78
79
80
81
82
83
	exit(EXIT_SUCCESS);
}


static void
org_cherry_start_repl(void)
{
	printf("Cherry Interpreter 0.1\n\n");
84

85
	struct org_cherry_environment* env = org_cherry_environment();
86
87
	
	org_cherry_env_push_exception_point(env);
Chris Müller's avatar
Chris Müller committed
88

89
90
91
	cy_byte_t* line = (cy_byte_t*) readline("> ");
	struct org_cherry_context* context = org_cherry_context_repl(line);
	
Chris Müller's avatar
Chris Müller committed
92
93
94
	while(1) {
		struct org_cherry_value* exp = org_cherry_read(context);

95
96
97
98
99
100
101
102
103
		if(!setjmp(EXCEPTION_JUMP(env))) {
			org_cherry_print(stdout, org_cherry_eval(env, exp));
			printf("\n");
		} else {
			fprintf(stderr, "EXCEPTION: ");
			org_cherry_print(stderr, EXCEPTION_DATA(env));
			fprintf(stderr, "\n");
		}

Chris Müller's avatar
Chris Müller committed
104
        free(line);
105
106
107

		line = (cy_byte_t*) readline("> ");
		org_cherry_context_repl_set_source(context, line);
Chris Müller's avatar
Chris Müller committed
108
	}
109
110

	org_cherry_env_pop_exception_point(env);
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
}


int 
main(int argc, char** argv)
{
	static struct option options[] = {
		{"help", no_argument, 0, 'h'},
		{"loadpath", optional_argument, 0, 'I'},
		{"main", optional_argument, 0, 'M'}
	};

	org_cherry_initialize(0);

	int ch;
	const char* filename = 0;
	const cy_byte_t* method = 0;
	struct org_cherry_ptrarray* load_path = org_cherry_ptrarray_new(4);
	struct org_cherry_value* arguments = org_cherry_emptylist;

	while( (ch = getopt_long(argc, argv, "hI:M:", options, 0)) != -1) {
		switch(ch) {
			case 'h':
				print_usage(stdout, argv[0]);
				exit(EXIT_SUCCESS);
			case 'I':
				org_cherry_ptrarray_append(load_path, optarg);
				break;
			case 'M':
				method = optarg;
				break;
			case '?':
				print_usage(stderr, argv[0]);
				exit(EXIT_FAILURE);
			default:
				fprintf(stderr, "???");
				exit(EXIT_FAILURE);
		}
	}

	if(optind < argc)
		filename = argv[optind++];

	while(optind < argc) {
		arguments = org_cherry_list_cons(org_cherry_string(argv[optind++]), arguments);
	}

Chris Müller's avatar
Chris Müller committed
158

159
	if(filename)
160
		org_cherry_process_file(filename, method, org_cherry_list_reverse(arguments));
161
162
	else
		org_cherry_start_repl();
163
164
165

	return EXIT_SUCCESS;
}