#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) { 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) { struct object *res; switch (op.type) { case TOKEN_PLUS: res = object_new(left->integer + right->integer); break; case TOKEN_MINUS: res = object_new(left->integer - right->integer); break; case TOKEN_ASTERISK: res = object_new(left->integer * right->integer); break; case TOKEN_SLASH: res = object_new(left->integer / right->integer); break; case TOKEN_LT: res = get_bool_object(left->integer < right->integer); break; case TOKEN_GT: res = get_bool_object(left->integer > right->integer); break; case TOKEN_EQ: res = get_bool_object(left->integer == right->integer); break; case TOKEN_NOTEQ: res = get_bool_object(left->integer != right->integer); break; default:; char buf[256]; res = new_error("unknown operator: %s %s %s", object_type_print(left->type), slice_sprint(&op.literal, buf), object_type_print(right->type)); break; } object_unref(left); object_unref(right); return res; } 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); } struct object *res; switch (op.type) { case TOKEN_EQ: res = get_bool_object(left->integer == right->integer); break; case TOKEN_NOTEQ: res = get_bool_object(left->integer != right->integer); break; default:; char buf[256]; if (left->type != right->type) { res = new_error("type mismatch: %s %s %s", object_type_print(left->type), slice_sprint(&op.literal, buf), object_type_print(right->type)); } else { res = new_error("unknown operator: %s %s %s", object_type_print(left->type), slice_sprint(&op.literal, buf), object_type_print(right->type)); } break; } object_unref(left); object_unref(right); return 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; }