DISABLE FDs (REMOVE ME).
[jackhill/mal.git] / c / step2_eval.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <unistd.h>
5
6 #include "types.h"
7 #include "readline.h"
8 #include "reader.h"
9
10 // Declarations
11 MalVal *EVAL(MalVal *ast, GHashTable *env);
12
13 // read
14 MalVal *READ(char prompt[], char *str) {
15 char *line;
16 MalVal *ast;
17 if (str) {
18 line = str;
19 } else {
20 line = _readline(prompt);
21 if (!line) {
22 _error("EOF");
23 return NULL;
24 }
25 }
26 ast = read_str(line);
27 if (!str) { MAL_GC_FREE(line); }
28 return ast;
29 }
30
31 // eval
32 MalVal *eval_ast(MalVal *ast, GHashTable *env) {
33 if (!ast || mal_error) return NULL;
34 if (ast->type == MAL_SYMBOL) {
35 //g_print("EVAL symbol: %s\n", ast->val.string);
36 // TODO: check if not found
37 MalVal *res = g_hash_table_lookup(env, ast->val.string);
38 assert(res, "'%s' not found", ast->val.string);
39 return res;
40 } else if ((ast->type == MAL_LIST) || (ast->type == MAL_VECTOR)) {
41 //g_print("EVAL sequential: %s\n", _pr_str(ast,1));
42 MalVal *el = _map2((MalVal *(*)(void*, void*))EVAL, ast, env);
43 if (!el || mal_error) return NULL;
44 el->type = ast->type;
45 return el;
46 } else if (ast->type == MAL_HASH_MAP) {
47 //g_print("EVAL hash_map: %s\n", _pr_str(ast,1));
48 GHashTableIter iter;
49 gpointer key, value;
50 MalVal *seq = malval_new_list(MAL_LIST,
51 g_array_sized_new(TRUE, TRUE, sizeof(MalVal*),
52 _count(ast)));
53 g_hash_table_iter_init (&iter, ast->val.hash_table);
54 while (g_hash_table_iter_next (&iter, &key, &value)) {
55 MalVal *kname = malval_new_string((char *)key);
56 g_array_append_val(seq->val.array, kname);
57 MalVal *new_val = EVAL((MalVal *)value, env);
58 g_array_append_val(seq->val.array, new_val);
59 }
60 return _hash_map(seq);
61 } else {
62 //g_print("EVAL scalar: %s\n", _pr_str(ast,1));
63 return ast;
64 }
65 }
66
67 MalVal *EVAL(MalVal *ast, GHashTable *env) {
68 if (!ast || mal_error) return NULL;
69 //g_print("EVAL: %s\n", _pr_str(ast,1));
70 if (ast->type != MAL_LIST) {
71 return eval_ast(ast, env);
72 }
73 if (!ast || mal_error) return NULL;
74
75 // apply list
76 //g_print("EVAL apply list: %s\n", _pr_str(ast,1));
77 if (_count(ast) == 0) { return ast; }
78 MalVal *a0 = _nth(ast, 0);
79 assert_type(a0, MAL_SYMBOL, "Cannot invoke %s", _pr_str(a0,1));
80 MalVal *el = eval_ast(ast, env);
81 if (!el || mal_error) { return NULL; }
82 MalVal *(*f)(void *, void*) = (MalVal *(*)(void*, void*))_first(el);
83 //g_print("eval_invoke el: %s\n", _pr_str(el,1));
84 return f(_nth(el, 1), _nth(el, 2));
85 }
86
87 // print
88 char *PRINT(MalVal *exp) {
89 if (mal_error) {
90 return NULL;
91 }
92 return _pr_str(exp,1);
93 }
94
95 // repl
96
97 // read and eval
98 MalVal *RE(GHashTable *env, char *prompt, char *str) {
99 MalVal *ast, *exp;
100 ast = READ(prompt, str);
101 if (!ast || mal_error) return NULL;
102 exp = EVAL(ast, env);
103 if (ast != exp) {
104 malval_free(ast); // Free input structure
105 }
106 return exp;
107 }
108
109 // Setup the initial REPL environment
110 GHashTable *repl_env;
111
112 WRAP_INTEGER_OP(plus,+)
113 WRAP_INTEGER_OP(minus,-)
114 WRAP_INTEGER_OP(multiply,*)
115 WRAP_INTEGER_OP(divide,/)
116
117 void init_repl_env() {
118 repl_env = g_hash_table_new(g_str_hash, g_str_equal);
119
120 g_hash_table_insert(repl_env, "+", int_plus);
121 g_hash_table_insert(repl_env, "-", int_minus);
122 g_hash_table_insert(repl_env, "*", int_multiply);
123 g_hash_table_insert(repl_env, "/", int_divide);
124 }
125
126 int main()
127 {
128 MalVal *exp;
129 char *output;
130 char prompt[100];
131
132 MAL_GC_SETUP();
133
134 // Set the initial prompt and environment
135 snprintf(prompt, sizeof(prompt), "user> ");
136 init_repl_env();
137
138 // repl loop
139 for(;;) {
140 exp = RE(repl_env, prompt, NULL);
141 if (mal_error && strcmp("EOF", mal_error->val.string) == 0) {
142 return 0;
143 }
144 output = PRINT(exp);
145
146 if (mal_error) {
147 fprintf(stderr, "Error: %s\n", _pr_str(mal_error,1));
148 malval_free(mal_error);
149 mal_error = NULL;
150 } else if (output) {
151 puts(output);
152 MAL_GC_FREE(output); // Free output string
153 }
154
155 //malval_free(exp); // Free evaluated expression
156 }
157 }