Пример #1
0
LakeVal *eval(LakeCtx *ctx, Env *env, LakeVal *expr)
{
  LakeVal *result;
  LakeList *list;

  switch (expr->type) {

    /* self evaluating types */
    case TYPE_BOOL:
    case TYPE_INT:
    case TYPE_STR:
      result = expr;
      break;

    case TYPE_SYM:
      result = env_get(env, (void *)SYM(expr));
      if (!result) {
        ERR("undefined variable: %s", sym_repr(SYM(expr)));
      }
      break;

    case TYPE_DLIST:
      ERR("malformed function call");
      result = NULL;
      break;

    case TYPE_COMM:
      result = NULL;
      break;

    case TYPE_LIST:
      list = LIST(expr);

      if (LIST_N(list) == 0) {
        result = expr;
      }
      else {
        if (is_special_form(ctx, list)) {
          result = eval_special_form(ctx, env, list);
        }
        else {
          LakeVal *fn = eval(ctx, env, LIST_VAL(list, 0));
          if (!fn) {
            return NULL;
          }
          LakeList *args = list_make_with_capacity(LIST_N(list) - 1);
          int i;
          LakeVal *v;
          for (i = 1; i < LIST_N(list); ++i) {
            v = eval(ctx, env, LIST_VAL(list, i));
            if (v != NULL) {
              list_append(args, v);
            }
            else {
              list_free(args);
              result = NULL;
              goto done;
            }
          }
          result = apply(ctx, fn, args);
        }
      }
      break;

    default:
      ERR("unrecognized value, type %d, size %zu bytes", expr->type, expr->size);
      DIE("we don't eval that around here!");
  }

  done: return result;
}
Пример #2
0
Value * evaluate(Environment *env, Value *expr) {

    EvaluationContext *ctx;
    Value *temp, *result;

    Value *operator;
    Value *operand_val, *operand_cons;
    Value *operands, *operands_end, *nil_value;
    int num_operands;

    /* Set up a new evaluation context and record our local variables, so that
     * the garbage-collector can see any temporary values we use.
     */
    ctx = push_new_evalctx(env, expr);
    evalctx_register(&temp);
    evalctx_register(&result);
    evalctx_register(&operator);
    evalctx_register(&operand_val);
    evalctx_register(&operand_cons);
    evalctx_register(&operands);
    evalctx_register(&operands_end);
    evalctx_register(&nil_value);

#ifdef VERBOSE_EVAL
    printf("\nEvaluating expression:  ");
    print_value(stdout, expr);
    printf("\n");
#endif

    /* If this is a special form, evaluate it.  Otherwise, this function will
     * simply pass the input through to the result.
     */
    result = eval_special_form(env, expr);
    if (result != expr)
        goto Done;    /* It was a special form. */

    /*
     * If the input is an atom, we need to resolve it to a value, using the
     * current environment.
     */

    if (is_atom(expr)) {
        /* Treat the atom as a name - resolve it to a value. */
        result = resolve_binding(env, expr->string_val);
        if (result == NULL) {
            result = make_error("couldn't resolve name \"%s\" to a value!",
                expr->string_val);
        }

        goto Done;
    }

    /*
     * If the input isn't an atom and isn't a cons-pair, then assume it's a
     * value that doesn't need evaluating, and just return it.
     */

    if (!is_cons_pair(expr)) {
        result = expr;
        goto Done;
    }

    /*
     * Evaluate operator into a lambda expression.
     */

    temp = get_car(expr);

    operator = evaluate(env, temp);
    if (is_error(operator)) {
        result = operator;
        goto Done;
    }
    if (!is_lambda(operator)) {
        result = make_error("operator is not a valid lambda expression");
        goto Done;
    }

#ifdef VERBOSE_EVAL
    printf("Operator:  ");
    print_value(stdout, operator);
    printf("\n");
#endif

    /*
     * Evaluate each operand into a value, and build a list up of the values.
     */

#ifdef VERBOSE_EVAL
    printf("Starting evaluation of operands.\n");
#endif

    num_operands = 0;
    operands_end = NULL;
    operands = nil_value = make_nil();

    temp = get_cdr(expr);
    while (is_cons_pair(temp)) {
        Value *raw_operand;

        num_operands++;

        /* This is the raw unevaluated value. */
        raw_operand = get_car(temp);

        /* Evaluate the raw input into a value. */

        operand_val = evaluate(env, raw_operand);
        if (is_error(operand_val)) {
            result = operand_val;
            goto Done;
        }

        operand_cons = make_cons(operand_val, nil_value);
        if (operands_end != NULL)
            set_cdr(operands_end, operand_cons);
        else
            operands = operand_cons;

        operands_end = operand_cons;

        temp = get_cdr(temp);
    }

    /*
     * Apply the operator to the operands, to generate a result.
     */

    if (operator->lambda_val->native_impl) {
        /* Native lambdas don't need an environment created for them.  Rather,
         * we just pass the list of arguments to the native function, and it
         * processes the arguments as needed.
         */
        result = operator->lambda_val->func(num_operands, operands);
    }
    else {
        /* These don't need registered on the explicit stack.  (I hope.) */
        Environment *child_env;
        Value *body_iter;

        /* It's an interpreted lambda.  Create a child environment, then
         * populate it with values based on the lambda's argument-specification
         * and the input operands.
         */
        child_env = make_environment(operator->lambda_val->parent_env);
        temp = bind_arguments(child_env, operator->lambda_val, operands);
        if (is_error(temp)) {
            result = temp;
            goto Done;
        }

        /* Evaluate each expression in the lambda, using the child environment.
         * The result of the last expression is the result of the lambda.
         */
        body_iter = operator->lambda_val->body;
        do {
            result = evaluate(child_env, get_car(body_iter));
            body_iter = get_cdr(body_iter);
        }
        while (!is_nil(body_iter));
    }

Done:

#ifdef VERBOSE_EVAL
    printf("Result:  ");
    print_value(stdout, result);
    printf("\n\n");
#endif

    /* Record the result and then perform garbage-collection. */
    pop_evalctx(result);
    collect_garbage();

    return result;
}
Пример #3
0
LObject *
lipa_eval (LObject *obj)
{
  gboolean found;
  LObject *tmp;

  if (!obj)
    return NULL;

  switch (obj->type)
    {
    case L_OBJ_LIST:

      tmp = eval_special_form (lipa_car (obj), lipa_cdr (obj), &found);

      if (found)
	{
	  return tmp;
	}
      else
	{
	  tmp = eval_function (lipa_car (obj), lipa_cdr (obj), &found);
	  if (found)
	    {
	      return tmp;
	    }
	  else
	    {
	      fputs ("can't be evaluated as a function: ", stdout);
	      lipa_print (obj);
	      fputc ('\n', stdout);
	    }
	}

      break;
      
    case L_OBJ_FUNCTION:
      fputs ("This should not be happning?!?!!?!?!\n", stderr);
      return NULL;
      break;

    case L_OBJ_SYMBOLNAME:
      return (lipa_eval(lipa_symbolname_lookup (L_SYMBOLNAME(obj)->str)));
      break;

    case L_OBJ_SYMBOL:
      return L_SYMBOL(obj).value;
      break;

      /* these evaluate to themselves */
    case L_OBJ_STRING:
    case L_OBJ_INT:
    case L_OBJ_FLOAT:
    case L_OBJ_CHAR:
    case L_OBJ_TRUE:
    case L_OBJ_FALSE:
    case L_OBJ_USEROBJECT:
      return obj;
      break;
    }

  return NULL;
}