~yerinalexey/sushi

bb45e0c27262dd517d9c9912a8dce607922c51ba — Alexey Yerin 7 months ago 95fc4ee
Implement pairs + cons/car/cdr
3 files changed, 68 insertions(+), 0 deletions(-)

M include/expr.h
M src/env.c
M src/expr.c
M include/expr.h => include/expr.h +2 -0
@@ 13,6 13,7 @@ enum expression_kind {

	/* Special forms */
	EXPR_LAMBDA,
	EXPR_PAIR,
	EXPR_QUOTE,
	EXPR_UNQUOTE,
};


@@ 35,6 36,7 @@ struct expression {
		char *symbol;

		struct expression *quoted;
		struct expression *pair[2];
	};
};


M src/env.c => src/env.c +51 -0
@@ 303,6 303,53 @@ env_if(struct location loc, struct list_expression *list,
}

static struct expression *
env_cons(struct location loc, struct list_expression *list,
	struct binding **bindings)
{
	if (!list || !list->next) {
		error(loc, "Not enough arguments");
	}

	struct expression *new = mkexpression();
	new->kind = EXPR_PAIR;
	new->pair[0] = eval(list->expr, bindings);
	new->pair[1] = eval(list->next->expr, bindings);
	return new;
}

static struct expression *
env_car(struct location loc, struct list_expression *list,
	struct binding **bindings)
{
	if (!list) {
		error(loc, "Not enough arguments");
	}

	struct expression *pair = eval(list->expr, bindings);
	if (pair->kind != EXPR_PAIR) {
		error(loc, "car must be used on a pair");
	}

	return expression_dup(pair->pair[0]);
}

static struct expression *
env_cdr(struct location loc, struct list_expression *list,
	struct binding **bindings)
{
	if (!list) {
		error(loc, "Not enough arguments");
	}

	struct expression *pair = eval(list->expr, bindings);
	if (pair->kind != EXPR_PAIR) {
		error(loc, "cdr must be used on a pair");
	}

	return expression_dup(pair->pair[1]);
}

static struct expression *
env_display(struct location loc, struct list_expression *list,
	struct binding **bindings)
{


@@ 348,6 395,10 @@ environment[] = {
	{ .name = "define", .func = &env_define },
	{ .name = "if",     .func = &env_if },

	{ .name = "cons", .func = &env_cons },
	{ .name = "car",  .func = &env_car },
	{ .name = "cdr",  .func = &env_cdr },

	{ .name = "display", .func = &env_display },
	{ .name = "newline", .func = &env_newline },


M src/expr.c => src/expr.c +15 -0
@@ 40,6 40,10 @@ expression_dup(struct expression *expr)
			newl = &(*newl)->next;
		}
		break;
	case EXPR_PAIR:
		new->pair[0] = expression_dup(expr->pair[0]);
		new->pair[1] = expression_dup(expr->pair[1]);
		break;
	case EXPR_STRING:
		new->string = xstrdup(expr->string);
		break;


@@ 74,6 78,10 @@ expression_free(struct expression *expr)
	case EXPR_UNQUOTE:
		expression_free(expr->quoted);
		break;
	case EXPR_PAIR:
		expression_free(expr->pair[0]);
		expression_free(expr->pair[1]);
		break;
	case EXPR_STRING:
		free(expr->string);
		break;


@@ 110,6 118,13 @@ expression_print(FILE *out, struct expression *expr)
		fputs(",", out);
		expression_print(out, expr->quoted);
		break;
	case EXPR_PAIR:
		fputs("(", out);
		expression_print(out, expr->pair[0]);
		fputs(" . ", out);
		expression_print(out, expr->pair[1]);
		fputs(")", out);
		break;
	case EXPR_STRING:
		fputs("\"", out);
		for (size_t i = 0; expr->string[i] != '\0'; i++) {