~yerinalexey/sushi

436e6f818e4db619b3be3c83378aa2b7b9005723 — Alexey Yerin 7 months ago 3f4e015
Implement 'set!'
4 files changed, 38 insertions(+), 14 deletions(-)

M include/eval.h
M src/env.c
M src/eval.c
M src/parser.c
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));
}