From c0cd4e5f199e8567ec3b5e216fbee27837d21bea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yaroslav=20de=20la=20Pe=C3=B1a=20Smirnov?= Date: Thu, 20 Jan 2022 02:34:32 +0300 Subject: init --- src/eval.c | 333 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 333 insertions(+) create mode 100644 src/eval.c (limited to 'src/eval.c') diff --git a/src/eval.c b/src/eval.c new file mode 100644 index 0000000..c1a6a10 --- /dev/null +++ b/src/eval.c @@ -0,0 +1,333 @@ +#include "eval.h" +#include "ast.h" +#include "object.h" +#include "token.h" + +#include +#include + +static struct object obj_null = { + OBJECT_NULL, + 2, + { 0 }, +}; +static struct object obj_true = { + OBJECT_BOOL, + 2, + .boolean = true, +}; +static struct object obj_false = { + OBJECT_BOOL, + 2, + .boolean = false, +}; + +static inline struct object * +get_bool_object(bool val) +{ + struct object *obj = val ? &obj_true : &obj_false; + return obj; +} + +static struct object * +new_error(char *fmt, ...) +{ + char *msg = malloc(1024); + struct object *obj = object_new(msg); + + va_list args; + va_start(args, fmt); + vsprintf(obj->error.msg, fmt, args); + va_end(args); + + return obj; +} + +static struct object * +eval_statements(struct environment *env, struct vector *sts) +{ + size_t i; + struct object *res; + struct statement *st; + vector_foreach(sts, i, st) { + res = eval(env, st); + if (res->type == OBJECT_RETURN || res->type == OBJECT_ERROR) { + return res; + } + } + return res; +} + +static inline struct object * +eval_bang_prefix_expression(struct environment *env, struct object *right) +{ + struct object *res; + res = get_bool_object(!right->integer); + object_unref(right); + return res; +} + +static inline struct object * +eval_minus_prefix_expression(struct environment *env, struct object *right) +{ + struct object *res; + if (right->type != OBJECT_INT) { + struct object *error = new_error("unknown operator: -%s", + object_type_print(right->type)); + object_unref(right); + return error; + } + res = object_new(-right->integer); + object_unref(right); + return res; +} + +static struct object * +eval_prefix_expression(struct environment *env, struct token op, + struct object *right) +{ + struct object *res; + switch (op.type) { + case TOKEN_BANG: + return eval_bang_prefix_expression(env, right); + case TOKEN_MINUS: + return eval_minus_prefix_expression(env, right); + default:; + char buf[256]; + struct object *error = new_error("unknown operator: %s%s", + slice_sprint(&op.literal, buf), object_type_print(right->type)); + object_unref(right); + return error; + } +} + +static inline struct object * +eval_integer_infix_expression(struct environment *env, struct token op, + struct object *left, struct object *right) +{ + bool bres; + struct object *ires; + switch (op.type) { + case TOKEN_PLUS: + ires = object_new(left->integer + right->integer); + break; + case TOKEN_MINUS: + ires = object_new(left->integer - right->integer); + break; + case TOKEN_ASTERISK: + ires = object_new(left->integer * right->integer); + break; + case TOKEN_SLASH: + ires = object_new(left->integer / right->integer); + break; + case TOKEN_LT: + bres = left->integer < right->integer; + goto boolres; + case TOKEN_GT: + bres = left->integer > right->integer; + goto boolres; + case TOKEN_EQ: + bres = left->integer == right->integer; + goto boolres; + case TOKEN_NOTEQ: + bres = left->integer != right->integer; + goto boolres; + default:; + char buf[256]; + struct object *error = new_error("unknown operator: %s %s %s", + object_type_print(left->type), slice_sprint(&op.literal, buf), + object_type_print(right->type)); + object_unref(left); + object_unref(right); + return error; + } + object_unref(left); + object_unref(right); + return ires; +boolres: + object_unref(left); + object_unref(right); + return get_bool_object(bres); +} + +static inline struct object * +eval_infix_expression(struct environment *env, struct token op, + struct object *left, struct object *right) +{ + if (left->type == OBJECT_INT && right->type == OBJECT_INT) { + return eval_integer_infix_expression(env, op, left, right); + } + bool res; + switch (op.type) { + case TOKEN_EQ: + res = left->integer == right->integer; + break; + case TOKEN_NOTEQ: + res = left->integer != right->integer; + break; + default:; + char buf[256]; + struct object *error; + if (left->type != right->type) { + error = new_error("type mismatch: %s %s %s", + object_type_print(left->type), slice_sprint(&op.literal, buf), + object_type_print(right->type)); + } else { + error = new_error("unknown operator: %s %s %s", + object_type_print(left->type), slice_sprint(&op.literal, buf), + object_type_print(right->type)); + } + object_unref(left); + object_unref(right); + return error; + } + object_unref(left); + object_unref(right); + return get_bool_object(res); +} + +static inline struct object * +eval_if_expression(struct environment *env, struct if_expression *expr) +{ + struct object *cond = eval(env, expr->condition); + struct object *res; + if (cond->boolean) { + res = eval(env, expr->consequence); + } else if (expr->alternative) { + res = eval(env, expr->alternative); + } else { + res = &obj_null; + } + object_unref(cond); + return res; +} + +static inline struct object * +eval_call_expression(struct environment *env, struct expression *expr) +{ + struct object *func = eval(env, expr->call.func); + if (func->type == OBJECT_ERROR) { + return func; + } else if (func->type != OBJECT_FUNC) { + char buf[256]; + struct object *err = new_error("not a function: %s", + object_sprint(func, buf)); + object_unref(func); + return err; + } + size_t i; + struct expression *arg; + struct environment *fenv = environment_new_enclosed(env); + vector_foreach(expr->call.arguments, i, arg) { + struct object *obj = eval(env, arg); + if (obj->type == OBJECT_ERROR) { + object_unref(func); + return obj; + } + struct expression *param = func->func.params->values[i]; + environment_set(fenv, param->ident.value, obj); + object_unref(obj); + } + struct object *res = eval(fenv, func->func.body); + if (res->type == OBJECT_RETURN) { + struct object *ret = res; + res = ret->retrn.value; + object_ref(res); + object_unref(ret); + } + object_unref(func); + environment_destroy(fenv); + return res; +} + +struct object * +eval_expression(struct environment *env, struct expression *expr) +{ + struct object *res = NULL; + switch (expr->type) { + case EXPRESSION_INT: + res = object_new(expr->integer.value); + return res; + case EXPRESSION_BOOL: + return expr->boolean.value ? &obj_true : &obj_false; + case EXPRESSION_PREFIX: + res = eval(env, expr->prefix.right); + if (res == OBJECT_ERROR) return res; + return eval_prefix_expression(env, expr->token, res); + case EXPRESSION_INFIX:; + struct object *left = eval(env, expr->infix.left); + if (left == OBJECT_ERROR) return res; + struct object *right = eval(env, expr->infix.right); + if (right == OBJECT_ERROR) { + object_unref(left); + return right; + } + return eval_infix_expression(env, expr->token, left, right); + case EXPRESSION_IF: + return eval_if_expression(env, &expr->cond); + case EXPRESSION_IDENT: + res = environment_get(env, &expr->ident.value); + if (!res) { + char ibuf[256]; + return new_error("not declared: %s", + slice_sprint(&expr->ident.value, ibuf)); + } + object_ref(res); + return res; + case EXPRESSION_FUNC: + res = object_new(expr); + return res; + case EXPRESSION_CALL: + return eval_call_expression(env, expr); + default: + return NULL; + } +} + +struct object * +eval_statement(struct environment *env, struct statement *st) +{ + struct object *val; + switch (st->type) { + case STATEMENT_EXPRESSION: + return eval(env, st->expr.expr); + case STATEMENT_BLOCK: + return eval_statements(env, st->block.statements); + case STATEMENT_RETURN: + val = eval(env, st->retrn.value); + if (val->type == OBJECT_ERROR) return val; + struct object *res = object_new(val); + return res; + case STATEMENT_LET: + val = eval(env, st->let.value); + if (val->type == OBJECT_ERROR) return val; + struct object *old = environment_set(env, st->let.name->value, val); + if (old) object_unref(old); + object_unref(val); + default: + return NULL; + } +} + +struct object * +eval_program(struct environment *env, struct program *prog) +{ + size_t i; + struct object *res = NULL; + struct statement *st; + vector_foreach(prog->statements, i, st) { + if (res) object_unref(res); + res = eval(env, st); + if (res) { + if (res->type == OBJECT_RETURN) { + struct object *val = res->retrn.value; + object_ref(val); + object_unref(res); + return val; + } else if (res->type == OBJECT_ERROR) { + return res; + } + } + } + return res; +} -- cgit v1.2.3