Esempio n. 1
0
Co<Expression> ExpressionFor::evaluate(Environment &env) const {
  Co<Expression> start_value = start->evaluate(env);
  Co<Expression> end_value = end->evaluate(env);
  Co<Expression> delta_value = delta->evaluate(env);

  ExpressionInteger *start_ivalue = dynamic_cast<ExpressionInteger *>(start_value.GetPointer());
  ExpressionInteger *end_ivalue = dynamic_cast<ExpressionInteger *>(end_value.GetPointer());
  ExpressionInteger *delta_ivalue = dynamic_cast<ExpressionInteger *>(delta_value.GetPointer());

  if (!start_ivalue) {
    throw MessagedException(start->getSourceLocation().toAnchor() + ": A for loop's starting value must be an integer. " + start->getSource() + " is not an integer.");
  }

  if (!end_ivalue) {
    throw MessagedException(end->getSourceLocation().toAnchor() + ": A for loop's ending value must be an integer. " + end->getSource() + " is not an integer.");
  }

  if (!delta_ivalue) {
    throw MessagedException(delta->getSourceLocation().toAnchor() + ": A for loop's increment value must be an integer. " + delta->getSource() + " is not an integer.");
  }

  int a = start_ivalue->toInteger();
  int b = end_ivalue->toInteger();
  int idelta = delta_ivalue->toInteger();
 
  Co<Expression> value = ExpressionUnit::getSingleton();

  if (idelta > 0) {
    if (is_inclusive) {
      ++b;
    }

    for (int i = a; i < b; i += idelta) {
      env.checkTimeout(getSourceLocation());
      iterator->assign(env, Co<Expression>(new ExpressionInteger(i)));
      value = body->evaluate(env);
    }
  } else {
    if (is_inclusive) {
      --b;
    }
    
    for (int i = a; i > b; i += idelta) {
      env.checkTimeout(getSourceLocation());
      iterator->assign(env, Co<Expression>(new ExpressionInteger(i)));
      value = body->evaluate(env);
    }
  }

  return value;
}
Co<Expression> ExpressionCallWithNamedParameters::evaluate(Environment &env) const {
  env.checkTimeout(getSourceLocation());

  Co<ExpressionClosure> closure = env[name];
  /* std::cout << "getSource(): " << getSource() << std::endl; */
  /* std::cout << "getSourceLocation(): " << getSourceLocation().toAnchor() << std::endl; */
  /* std::cout << "closure->getSourceLocation(): " << closure->getSourceLocation().toAnchor() << std::endl; */
  if (closure.IsNull()) {
    throw MessagedException(getSourceLocation().toAnchor() + ": No function named " + name + " is defined.");
  }
  /* closure->setSource(getSource(), getSourceLocation()); */

  Co<ExpressionDefine> define = closure->getDefine();
  Co<Environment> closure_env(new Environment(*closure->getEnvironment()));

  // Before trying to execute this business, let's make certain the user didn't
  // pass any named parameters that don't apply. Having extras isn't going to
  // stop us from executing the function, but it probably means the caller has
  // some different intent.
  set<string> formal_names = define->getFormalNames();
  for (bindings_t::const_iterator i = bindings.begin();
       i != bindings.end();
       ++i) {
    if (formal_names.find(i->first) == formal_names.end()) {
      throw MessagedException(getSourceLocation().toAnchor() + ": I saw that you passed a parameter named " + i->first + " to function " + define->getName() + ", but " + define->getName() + " doesn't accept a parameter named " + i->first + ".");
    }
  }

  // Having cleared the appropriateness of the bindings, let's start evaluating.
  for (unsigned int i = 0; i < define->getArity(); ++i) {
    const FormalParameter &formal = define->getFormal(i);
    bool is_lazy = formal.getEvaluationMode() == FormalParameter::LAZY;

    // Look up parameter name in enumerated bindings first. If we find an
    // explicit parameter with that name, use its value.
    bindings_t::const_iterator match = bindings.find(formal.getName());
    Co<ExpressionDefine> parameter_define;
    Co<ExpressionDefine> parameter_closure;
    if (match != bindings.end()) {
      parameter_define = Co<ExpressionDefine>(new ExpressionDefine(formal.getName(), is_lazy ? match->second : match->second->evaluate(env)));
      parameter_closure = Co<ExpressionClosure>(new ExpressionClosure(parameter_define, is_lazy ? env : Environment()));
      parameter_closure->setSource(match->second->getSource(), match->second->getSourceLocation());
    } else if (!formal.getDefaultValue().IsNull()) {
      parameter_define = Co<ExpressionDefine>(new ExpressionDefine(formal.getName(), formal.getDefaultValue()->evaluate(env)));
      parameter_closure = Co<ExpressionClosure>(new ExpressionClosure(parameter_define, Environment()));
      parameter_closure->setSource(formal.getDefaultValue()->getSource(), formal.getDefaultValue()->getSourceLocation());

    // UPDATE: disallow implicits. They work, but their benefit is small and
    // risk of confusion is too high.
    // If no such parameter was enumerated, checking for a binding with that
    // name in the surrounding environment at the time of the call.
    /* else if (env.isBound(formal.getName())) { */
      /* Co<Expression> closure = env[formal.getName()]; */
      /* parameter_define = Co<ExpressionDefine>(new ExpressionDefine(formal.getName(), is_lazy ? closure : closure->evaluate(env))); */
      /* parameter_closure = Co<ExpressionClosure>(new ExpressionClosure(parameter_define, is_lazy ? env : Environment())); */
      /* parameter_closure->setSource(closure->getSource(), closure->getSourceLocation()); */
    } else {
      throw MessagedException(getSourceLocation().toAnchor() + ": Function " + define->getName() + " expects a parameter named " + formal.getName() + ". No such parameter was provided and no variable with that name was defined.");
    }

    closure_env->replace(define->getFormal(i).getName(), parameter_closure);
  }

  try {
    return closure->evaluate(*closure_env);
  } catch (Co<Expression> return_value) {
    return return_value;
  } catch (UnlocatedException e) {
    throw MessagedException(getSourceLocation().toAnchor() + ": " + e.GetMessage());
  }
}