Value* Value_eval(const Value* val, const Context* ctx) { if(val == NULL) return ValErr(nullError()); Value* ret; Variable* var; switch(val->type) { /* These can be evaluated to a simpler form */ case VAL_EXPR: ret = BinOp_eval(val->expr, ctx); break; case VAL_UNARY: ret = UnOp_eval(val->term, ctx); break; case VAL_CALL: ret = FuncCall_eval(val->call, ctx); break; case VAL_FRAC: ret = Value_copy(val); Fraction_reduce(ret); break; case VAL_VAR: var = Variable_get(ctx, val->name); if(var) { ret = Variable_eval(var, ctx); } else { ret = ValErr(varNotFound(val->name)); } break; case VAL_VEC: ret = Vector_eval(val->vec, ctx); break; /* These can't be simplified, so just copy them */ case VAL_INT: case VAL_REAL: case VAL_NEG: case VAL_ERR: ret = Value_copy(val); break; default: /* Shouldn't be reached */ badValType(val->type); } return ret; }
Value* Expression_eval(Expression* expr, Context* ctx) { Value* ret; Variable* var = expr->var; if(var->type == VAR_VALUE) { /* Evaluate right side */ ret = Value_eval(var->val, ctx); /* If an error occurred, bail */ if(ret->type == VAL_ERR) return ret; /* Variable assignment? */ if(ret->type == VAL_VAR) { /* This means ret must be a function */ Variable* func = Variable_get(ctx, ret->name); if(func == NULL) { Value* err = ValErr(varNotFound(ret->name)); Value_free(ret); return err; } if(func->type == VAR_BUILTIN) { Value_free(ret); return ValErr(typeError("Cannot assign a variable to a builtin value.")); } if(var->name != NULL) { Context_setGlobal(ctx, var->name, Variable_copy(func)); } } else { /* This means ret must be a Value */ Value_free(var->val); var->val = Value_copy(ret); /* Update ans */ Context_setGlobal(ctx, "ans", Variable_copy(var)); /* Save the newly evaluated variable */ if(var->name != NULL) Context_setGlobal(ctx, var->name, Variable_copy(var)); } } else if(var->type == VAR_FUNC) { ret = ValVar(var->name); Context_setGlobal(ctx, var->name, Variable_copy(var)); } else { badVarType(var->type); } return ret; }
Value* Value_coerce(const Value* val, const Context* ctx) { Value* ret = Value_eval(val, ctx); if(ret->type == VAL_VAR) { Variable* var = Variable_get(ctx, ret->name); if(var == NULL) { Value* tmp = ValErr(varNotFound(ret->name)); Value_free(ret); ret = tmp; } else { ret = Variable_coerce(var, ctx); } } return ret; }