aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOskari Timperi <oskari.timperi@iki.fi>2014-05-15 23:44:24 +0300
committerOskari Timperi <oskari.timperi@iki.fi>2014-05-15 23:44:24 +0300
commita1a0fa8aba7e8a33d5fa6c9ace10338296615edc (patch)
tree8eb948dfbd7112ef3ff60c308730e1d86c7fd59b
parentfed18ccb88e03f511317ca593d9ad10038451d17 (diff)
downloadlispish-a1a0fa8aba7e8a33d5fa6c9ace10338296615edc.tar.gz
lispish-a1a0fa8aba7e8a33d5fa6c9ace10338296615edc.zip
eval symbols and allow defining variables
-rw-r--r--eval.c175
1 files changed, 111 insertions, 64 deletions
diff --git a/eval.c b/eval.c
index 0addb86..f4624cf 100644
--- a/eval.c
+++ b/eval.c
@@ -2,6 +2,7 @@
#include "list.h"
#include "atom.h"
#include "parse.h"
+#include "env.h"
#include <stdio.h>
#include <string.h>
@@ -87,6 +88,22 @@ struct list *eval_str(const char *str)
struct list *eval_env(struct list *expr, struct list *env)
{
+ if (IS_SYM(expr))
+ {
+ struct atom *atom = env_lookup(env, LIST_GET_ATOM(expr)->str.str);
+
+ if (atom)
+ {
+ return list_append(NULL, atom);
+ }
+ else
+ {
+ printf("error: undefined variable: %s\n",
+ LIST_GET_ATOM(expr)->str.str);
+ return list_append(NULL, &nil_atom);
+ }
+ }
+
if (!IS_LIST(expr))
return expr;
@@ -232,6 +249,30 @@ struct list *eval_env(struct list *expr, struct list *env)
return list_append(NULL, atom_new_int(result));
}
+ else if (strcmp(sym, "define") == 0)
+ {
+ struct list *expr_name = CDR(l);
+ struct list *expr_value = CDR(expr_name);
+
+ if (!expr_name || !expr_value)
+ {
+ printf("error: define takes two arguments\n");
+ return list_append(NULL, &nil_atom);
+ }
+
+ if (!IS_SYM(expr_name))
+ {
+ printf("error: define: first arg must be symbol\n");
+ return list_append(NULL, &nil_atom);
+ }
+
+ expr_value = eval_env(expr_value, env);
+
+ env_set(env, LIST_GET_ATOM(expr_name)->str.str,
+ LIST_GET_ATOM(expr_value));
+
+ return list_append(NULL, expr_value);
+ }
}
else if (IS_LIST(l))
{
@@ -255,97 +296,103 @@ struct list *eval_str_env(const char *expr, struct list *env)
#include "test_util.h"
-TEST(eval)
+TEST(nested_expression)
{
- struct list *result;
- int pos;
-
-#define EVAL(EXPR) \
- pos = 0; \
- result = eval(parse((EXPR), &pos))
-
-#define ARITHMETIC_TEST(EXPR, RESULT) \
- EVAL(EXPR); \
- ASSERT_EQ(ATOM_INT, ATOM_TYPE(result)); \
- ASSERT_EQ(RESULT, LIST_GET_ATOM(result)->l)
-
- ARITHMETIC_TEST("(+ 1 2)", 3);
- ARITHMETIC_TEST("(- 5 10)", -5);
- ARITHMETIC_TEST("(/ 42 2)", 21);
- ARITHMETIC_TEST("(* 5 10)", 50);
- ARITHMETIC_TEST("(* (* 2 (+ 1 1)) 2)", 8);
+ struct list *result = eval_str("(eq #f (> (- (+ 1 3) (* 2 (mod 7 4))) 4))");
+ ASSERT_TRUE(result != NULL);
+ ASSERT_TRUE(IS_TRUE(result));
+}
-#undef ARITHMETIC_TEST
+TEST(basic_if)
+{
+ struct list *result = eval_str("(if #t 42 1000)");
+ ASSERT_TRUE(result != NULL);
+ ASSERT_EQ(ATOM_INT, ATOM_TYPE(result));
+ ASSERT_EQ(42, LIST_GET_ATOM(result)->l);
+}
-#define EQ_TEST(EXPR, RESULT) \
- EVAL(EXPR); \
- ASSERT_EQ(result, RESULT)
+TEST(if_with_sub_expressions)
+{
+ struct list *result = eval_str("(if (> 1 2) (- 1000 1) (+ 40 (- 3 1)))");
+ ASSERT_TRUE(result != NULL);
+ ASSERT_EQ(ATOM_INT, ATOM_TYPE(result));
+ ASSERT_EQ(42, LIST_GET_ATOM(result)->l);
+}
-#define EQ_TEST_T(EXPR) EVAL(EXPR); ASSERT(IS_TRUE(result))
-#define EQ_TEST_F(EXPR) EVAL(EXPR); ASSERT(IS_FALSE(result))
+/* EVALUTE WITH ENVIRONMENT TESTS */
- EQ_TEST_T("(eq 1 1)");
- EQ_TEST_T("(eq (+ 1 1) 2)");
- EQ_TEST_T("(eq (quote (1 2 3)) (quote (1 2 3)))");
+TEST(evaluate_symbol)
+{
+ struct list *env = env_new();
+ env_set(env, "foo", atom_new_int(42));
- EQ_TEST_T("(eq \"eka\" \"eka\"");
- EQ_TEST_F("(eq \"eka\" eka)");
- EQ_TEST_F("(eq \"eka\" 100)");
- EQ_TEST_F("(eq \"eka\" \"toka\"");
+ struct list *result = eval_str_env("foo", env);
- EQ_TEST_T("(eq eka eka)");
- EQ_TEST_F("(eq eka toka)");
+ ASSERT_TRUE(result != NULL);
+ ASSERT_EQ(ATOM_INT, ATOM_TYPE(result));
+ ASSERT_EQ(42, LIST_GET_ATOM(result)->l);
+}
- EQ_TEST_F("(eq 1 2)");
- EQ_TEST_F("(eq 1 (- 1 1))");
- EQ_TEST_F("(eq (quote (1)) (quote (1 2 3)))");
+TEST(evaluate_missing_symbol)
+{
+ struct list *env = env_new();
- EQ_TEST_T("(eq (quote (1 2)) '(1 2))");
- EQ_TEST_T("(eq 'bar 'bar)");
- EQ_TEST_F("(eq 'foo 'bar)");
- EQ_TEST_T("(eq (quote bar) 'bar)");
- EQ_TEST_F("(eq (quote foo) 'bar)");
+ struct list *result = eval_str_env("foo", env);
- EQ_TEST_F("(> 1 2)");
- EQ_TEST_T("(> 2 1)");
+ ASSERT_TRUE(result != NULL);
+ ASSERT_EQ(ATOM_NIL, ATOM_TYPE(result));
+}
-#undef EQ_TEST_F
-#undef EQ_TEST_T
-#undef EQ_TEST
+TEST(define)
+{
+ struct list *env = env_new();
- EVAL("(if #t 1 2)");
- ASSERT_EQ(1, LIST_GET_ATOM(result)->l);
+ struct list *result = eval_str_env("(define x 100)", env);
- EVAL("(if #t (+ 1 1) (* 2 2))");
- ASSERT_EQ(2, LIST_GET_ATOM(result)->l);
+ ASSERT_TRUE(result != NULL);
- EVAL("(if #f (+ 1 1) (* 2 2))");
- ASSERT_EQ(4, LIST_GET_ATOM(result)->l);
+ struct atom *atom = env_lookup(env, "x");
-#undef EVAL
+ ASSERT_TRUE(atom != NULL);
+ ASSERT_EQ(ATOM_INT, atom->type);
+ ASSERT_EQ(100, atom->l);
}
-TEST(nested_expression)
+TEST(define_missing_value)
{
- struct list *result = eval_str("(eq #f (> (- (+ 1 3) (* 2 (mod 7 4))) 4))");
+ struct list *env = env_new();
+
+ struct list *result = eval_str_env("(define x)", env);
ASSERT_TRUE(result != NULL);
- ASSERT_TRUE(IS_TRUE(result));
+ ASSERT_EQ(ATOM_NIL, ATOM_TYPE(result));
+
+ struct atom *atom = env_lookup(env, "x");
+ ASSERT_TRUE(atom == NULL);
}
-TEST(basic_if)
+TEST(define_nonsymbol_as_name)
{
- struct list *result = eval_str("(if #t 42 1000)");
+ struct list *env = env_new();
+
+ struct list *result = eval_str_env("(define 1 100)", env);
ASSERT_TRUE(result != NULL);
- ASSERT_EQ(ATOM_INT, ATOM_TYPE(result));
- ASSERT_EQ(42, LIST_GET_ATOM(result)->l);
+ ASSERT_EQ(ATOM_NIL, ATOM_TYPE(result));
}
-TEST(if_with_sub_expressions)
+TEST(define_with_val_as_expr)
{
- struct list *result = eval_str("(if (> 1 2) (- 1000 1) (+ 40 (- 3 1)))");
+ struct list *env = env_new();
+
+ struct list *result = eval_str_env("(define x (* 3 3))", env);
+
ASSERT_TRUE(result != NULL);
- ASSERT_EQ(ATOM_INT, ATOM_TYPE(result));
- ASSERT_EQ(42, LIST_GET_ATOM(result)->l);
+
+ struct atom *atom = env_lookup(env, "x");
+
+ ASSERT_TRUE(atom != NULL);
+ ASSERT_EQ(ATOM_INT, atom->type);
+ ASSERT_EQ(9, atom->l);
}
+
#endif /* BUILD_TEST */