M include/eval.h => include/eval.h +6 -2
@@ 2,7 2,11 @@
#define SUSHI_EVAL_H
struct expression;
-struct binding;
+struct binding {
+ char *name;
+ struct expression *expr;
+ struct binding *next;
+};
/*
* Evaluates an expression.
@@ 13,7 17,7 @@ struct binding;
*/
struct expression *eval(struct expression *expr, struct binding **);
-struct expression *binding_lookup(struct binding *binds, char *symbol);
+struct binding *binding_lookup(struct binding *binds, char *symbol);
void binding_insert(struct binding **binds, char *symbol,
struct expression *value);
M src/env.c => src/env.c +25 -0
@@ 284,6 284,30 @@ env_define(struct location loc, struct list_expression *list,
}
static struct expression *
+env_set(struct location loc, struct list_expression *list,
+ struct binding **bindings)
+{
+ if (!list || !list->next) {
+ error(loc, "Not enough arguments");
+ }
+
+ struct expression *handle = list->expr;
+ if (handle->kind != EXPR_SYMBOL) {
+ error(loc, "Invalid set!; expected a symbol");
+ }
+ struct expression *value = eval(list->next->expr, bindings);
+
+ struct binding *bind = binding_lookup(*bindings, handle->symbol);
+ if (!bind) {
+ error(loc, "Undefined symbol '%s'", handle->symbol);
+ }
+ expression_free(bind->expr);
+ bind->expr = value;
+
+ return mknil();
+}
+
+static struct expression *
env_if(struct location loc, struct list_expression *list,
struct binding **bindings)
{
@@ 393,6 417,7 @@ environment[] = {
{ .name = "or", .func = &env_or },
{ .name = "define", .func = &env_define },
+ { .name = "set!", .func = &env_set },
{ .name = "if", .func = &env_if },
{ .name = "cons", .func = &env_cons },
M src/eval.c => src/eval.c +6 -12
@@ 2,22 2,17 @@
#include <stdbool.h>
#include <string.h>
#include "env.h"
+#include "eval.h"
#include "expr.h"
#include "parser.h"
#include "utils.h"
-struct binding {
- char *name;
- struct expression *expr;
- struct binding *next;
-};
-
-struct expression *
+struct binding *
binding_lookup(struct binding *binds, char *symbol)
{
while (binds) {
if (strcmp(binds->name, symbol) == 0) {
- return binds->expr;
+ return binds;
}
binds = binds->next;
@@ 100,12 95,11 @@ eval(struct expression *expr, struct binding **bindings)
case EXPR_LIST:
return eval_list(expr, bindings);
case EXPR_SYMBOL: {
- struct expression *value = binding_lookup(*bindings,
- expr->symbol);
- if (!value) {
+ struct binding *bind = binding_lookup(*bindings, expr->symbol);
+ if (!bind) {
return mknil();
}
- return expression_dup(value);
+ return expression_dup(bind->expr);
}
case EXPR_QUOTE:
return expression_dup(expr->quoted);
M src/parser.c => src/parser.c +1 -0
@@ 149,6 149,7 @@ is_symbol(char ch, bool start)
|| ch == '<'
|| ch == '_'
|| ch == '-'
+ || ch == '!'
|| (start ? false : isdigit(ch));
}