lval* lval_call(lenv* e, lval* f, lval* a) {

  /* If Builtin then simply apply that */
  if (f->builtin) { return f->builtin(e, a); }

  /* Record Argument Counts */
  int given = a->count;
  int total = f->formals->count;

  /* While arguments still remain to be processed */
  while (a->count) {

    /* If we've ran out of formal arguments to bind */
    if (f->formals->count == 0) {
      lval_del(a);
      return lval_err("Function passed too many arguments. Got %i, Expected %i.", given, total);
    }

    /* Pop the first symbol from the formals */
    lval* sym = lval_pop(f->formals, 0);

    /* Special Case to deal with '&' */
    if (strcmp(sym->sym, "&") == 0) {

      /* Ensure '&' is followed by another symbol */
      if (f->formals->count != 1) {
        lval_del(a);
        return lval_err("Function format invalid. Symbol '&' not followed by single symbol.");
      }

      /* Next formal should be bound to remaining arguments */
      lval* nsym = lval_pop(f->formals, 0);
      lenv_put(f->env, nsym, builtin_list(e, a));
      lval_del(sym); lval_del(nsym);
      break;
    }

    /* Pop the next argument from the list */
    lval* val = lval_pop(a, 0);

    /* Bind a copy into the function's environment */
    lenv_put(f->env, sym, val);

    /* Delete symbol and value */
    lval_del(sym); lval_del(val);
  }

  /* Argument list is now bound so can be cleaned up */
  lval_del(a);

  /* If '&' remains in formal list it should be bound to empty list */
  if (f->formals->count > 0 &&
    strcmp(f->formals->cell[0]->sym, "&") == 0) {

    /* Check to ensure that & is not passed invalidly. */
    if (f->formals->count != 2) {
      return lval_err("Function format invalid. Symbol '&' not followed by single symbol.");
    }

    /* Pop and delete '&' symbol */
    lval_del(lval_pop(f->formals, 0));

    /* Pop next symbol and create empty list */
    lval* sym = lval_pop(f->formals, 0);
    lval* val = lval_qexpr();

    /* Bind to environment and delete */
    lenv_put(f->env, sym, val);
    lval_del(sym); lval_del(val);
  }

  /* If all formals have been bound evaluate */
  if (f->formals->count == 0) {

    /* Set Function Environment parent to current evaluation Environment */
    f->env->par = e;

    /* Evaluate and return */
    return builtin_eval(f->env, lval_add(lval_sexpr(), lval_copy(f->body)));
  } else {
    /* Otherwise return partially evaluated function */
    return lval_copy(f);
  }

}
Exemple #2
0
lval* lval_call(lenv* e, lval* f, lval* a) {
    if (f->builtin) {
        return f->builtin(e, a);
    }

    int given = a->count;
    int total = f->formals->count;

    while (a->count) {
        if (f->formals->count == 0) {
            lval_del(a);
            return lval_err("Function passed too many arguments. Expected %i, Got %i.", total, given);
        }

        lval* sym = lval_pop(f->formals, 0);

        // Variadic operator
        if (strcmp(sym->sym, "&") == 0){
            if (f->formals->count != 1) {
                lval_del(a);
                return lval_err("Function format invalid. "
                        "Symbol '&' not followed by a single symbol");
            }

            lval* nsym = lval_pop(f->formals, 0);
            lenv_put(f->env, nsym, builtin_list(e, a));
            lval_del(sym);
            lval_del(nsym);
            break;
        }

        lval* val = lval_pop(a, 0);
        lenv_put(f->env, sym, val);
        lval_del(val);
        lval_del(sym);
    }

    lval_del(a);

    // If '&' remains in formal list bind to empty list
    if (f->formals->count > 0 &&
            strcmp(f->formals->cell[0]->sym, "&") == 0) {
        if (f->formals->count != 2) {
            return lval_err("Function format invalid. "
                    "Symbol '&' not followed by a single symbol");
        }

        lval_del(lval_pop(f->formals, 0));

        lval* sym = lval_pop(f->formals, 0);
        lval* val = lval_qexpr();

        lenv_put(f->env, sym, val);
        lval_del(val);
        lval_del(sym);
    }

    if (f->formals->count == 0) {
        f->env->par = e;
        return builtin_eval(f->env, lval_add(lval_sexpr(), lval_copy(f->body)));
    } else {
        return lval_copy(f);
    }
}
Exemple #3
0
Value* tl_val_call(Env* e, Value* fn, Value* args) {
  if(fn->builtin) { return fn->builtin(e, args); }

  int given = args->count;
  int total = fn->formals->count;

  while (args->count) {
    if (fn->formals->count == 0) {
      tl_val_delete(args);
      return tl_val_error(
          "Function passed too many arguments. "
          "Got %i, expected %i.", given, total);
    }

    Value* sym = tl_val_pop(fn->formals, 0);

    if (strcmp(sym->sym, "&") == 0) {
      if (fn->formals->count != 1) {
        tl_val_delete(args);
        return tl_val_error("Function format invalid."
            "Symbol '&' not followed by single symbol");
      }

      Value* symbols = tl_val_pop(fn->formals, 0);
      tl_env_put(fn->env, symbols, builtin_list(e, args));
      tl_val_delete(sym);
      tl_val_delete(symbols);
      break;
    }

    Value* val = tl_val_pop(args, 0);
    tl_env_put(fn->env, sym, val);
    tl_val_delete(sym);
    tl_val_delete(val);
  }

  if (fn->formals->count > 0 && strcmp(fn->formals->cell[0]->sym, "&") == 0) {
    if (fn->formals->count != 2) {
      return tl_val_error("Function format invalid."
          "Symbol '&' not followed by single symbol");
    }

    tl_val_delete(tl_val_pop(fn->formals, 0));
    Value* symbol = tl_val_pop(fn->formals, 0);
    Value* value  = tl_val_qexpr();

    tl_env_put(e, symbol, value);
    tl_val_delete(symbol);
    tl_val_delete(value);
  }

  tl_val_delete(args);

  if (fn->formals->count == 0) {
    // Eval and return if all formals have been bound
    fn->env->parent = e;
    return builtin_eval(fn->env,
        tl_val_add(tl_val_sexpr(), tl_val_copy(fn->body)));
  } else {
    // Partially evaluated function
    return tl_val_copy(fn);
  }
}