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