All: move some fns to core. Major cleanup.
[jackhill/mal.git] / c / step2_eval.c
CommitLineData
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
10MalVal *EVAL(MalVal *ast, GHashTable *env);
11
12// read
13MalVal *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
31MalVal *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
64MalVal *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// print
85char *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
98MalVal *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
110GHashTable *repl_env;
111
8cb5cda4 112
31690700
JM
113void 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
127int 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}