compiler/resolution/preFold.cpp
/*
  To mimic a function call, we create a .this method for the parent class.
  This will allow the object to look and feel like a first-class function,
  by both being an object and being invoked using parentheses syntax.

  Children of the parent class will override this method and wrap the
  function that is being used as a first-class value.

  To focus on just the types of the arguments and not their names or
  default values, we use the parent method's names and types as the basis
  for all children which override it.

  The function is put at the highest scope so that all functions of a given
  type will share the same parent class.
*/
To mimic a function call, we create a .this method for the parent class.
This will allow the object to look and feel like a first-class function,
by both being an object and being invoked using parentheses syntax.

Children of the parent class will override this method and wrap the
function that is being used as a first-class value.

To focus on just the types of the arguments and not their names or
default values, we use the parent method's names and types as the basis
for all children which override it.

The function is put at the highest scope so that all functions of a given
type will share the same parent class.
To mimic a function call we create a . this method for the parent class . This will allow the object to look and feel like a first - class function by both being an object and being invoked using parentheses syntax . Children of the parent class will override this method and wrap the function that is being used as a first - class value . To focus on just the types of the arguments and not their names or default values we use the parent method ' s names and types as the basis for all children which override it . The function is put at the highest scope so that all functions of a given type will share the same parent class .
static FnSymbol* createAndInsertFunParentMethod(CallExpr*      call,
                                                AggregateType* parent,
                                                AList&         arg_list,
                                                bool           isFormal,
                                                Type*          retType) {
     * The return type itself is not actually stored as a member variable
     * A function that returns void will similarly cause a call to retType
       to return void, which is to say it doesn't return anything.  This is
       maybe not terribly intuitive to the user, but should be resolved
       when "void" becomes a fully-featured type.
  {
    FnSymbol* rtGetter = new FnSymbol("retType");
    rtGetter->addFlag(FLAG_NO_IMPLICIT_COPY);
    rtGetter->addFlag(FLAG_INLINE);
    rtGetter->addFlag(FLAG_COMPILER_GENERATED);
    rtGetter->retTag = RET_TYPE;
    rtGetter->insertFormalAtTail(new ArgSymbol(INTENT_BLANK,
                                               "_mt",
                                               dtMethodToken));
    ArgSymbol* _this = new ArgSymbol(INTENT_BLANK, "this", parent);
    _this->addFlag(FLAG_ARG_THIS);
    rtGetter->insertFormalAtTail(_this);
    rtGetter->insertAtTail(new CallExpr(PRIM_RETURN, retType->symbol));
    DefExpr* def = new DefExpr(rtGetter);
    parent->symbol->defPoint->insertBefore(def);
    normalize(rtGetter);
    parent->methods.add(rtGetter);
    rtGetter->setMethod(true);
    rtGetter->addFlag(FLAG_METHOD_PRIMARY);
    rtGetter->cname = astr("chpl_get_",
                           parent->symbol->cname,
                           "_",
                           rtGetter->cname);
    rtGetter->addFlag(FLAG_NO_PARENS);
    rtGetter->_this = _this;
  }
   Add a "getter" method that returns the tuple of argument types
   for the function
  {
    FnSymbol* atGetter = new FnSymbol("argTypes");
    atGetter->addFlag(FLAG_NO_IMPLICIT_COPY);
    atGetter->addFlag(FLAG_INLINE);
    atGetter->addFlag(FLAG_COMPILER_GENERATED);
    atGetter->retTag = RET_TYPE;
    atGetter->insertFormalAtTail(new ArgSymbol(INTENT_BLANK,
                                               "_mt",
                                               dtMethodToken));
    CallExpr* expr = new CallExpr(PRIM_ACTUALS_LIST);
    if (isFormal) {
      for_alist(formalExpr, arg_list) {
        DefExpr*   dExp = toDefExpr(formalExpr);
        ArgSymbol* fArg = toArgSymbol(dExp->sym);
        expr->insertAtTail(fArg->type->symbol);
      }
    }
    else {
      for_alist(actualExpr, arg_list) {
        if (actualExpr != arg_list.tail) {
          SymExpr* sExpr = toSymExpr(actualExpr);
          expr->insertAtTail(sExpr->symbol()->type->symbol);
        }
      }
    }
    ArgSymbol* _this = new ArgSymbol(INTENT_BLANK, "this", parent);
    _this->addFlag(FLAG_ARG_THIS);
    atGetter->insertFormalAtTail(_this);
    atGetter->insertAtTail(new CallExpr(PRIM_RETURN,
                                        new CallExpr("_build_tuple", expr)));
    DefExpr* def = new DefExpr(atGetter);
    parent->symbol->defPoint->insertBefore(def);
    normalize(atGetter);
    parent->methods.add(atGetter);
    atGetter->setMethod(true);
    atGetter->addFlag(FLAG_METHOD_PRIMARY);
    atGetter->cname = astr("chpl_get_",
                           parent->symbol->cname, "_",
                           atGetter->cname);
    atGetter->addFlag(FLAG_NO_PARENS);
    atGetter->_this = _this;
  }
  FnSymbol* parent_method = new FnSymbol("this");
  parent_method->addFlag(FLAG_FIRST_CLASS_FUNCTION_INVOCATION);
  parent_method->addFlag(FLAG_COMPILER_GENERATED);
  parent_method->insertFormalAtTail(new ArgSymbol(INTENT_BLANK,
                                                  "_mt",
                                                  dtMethodToken));
  parent_method->setMethod(true);
  ArgSymbol* thisParentSymbol = new ArgSymbol(INTENT_BLANK, "this", parent);
  thisParentSymbol->addFlag(FLAG_ARG_THIS);
  parent_method->insertFormalAtTail(thisParentSymbol);
  parent_method->_this = thisParentSymbol;
  int i       = 0;
  int alength = arg_list.length;
   We handle the arg list differently depending on if it's a list of
   formal args or actual args
  if (isFormal) {
    for_alist(formalExpr, arg_list) {
      DefExpr* dExp = toDefExpr(formalExpr);
      ArgSymbol* fArg = toArgSymbol(dExp->sym);
      if (fArg->type != dtVoid) {
        ArgSymbol* newFormal = new ArgSymbol(INTENT_BLANK,
                                             fArg->name,
                                             fArg->type);
        if (fArg->typeExpr)
          newFormal->typeExpr = fArg->typeExpr->copy();
        parent_method->insertFormalAtTail(newFormal);
      }
    }
  } else {
    char name_buffer[100];
    int  name_index = 0;
    for_alist(actualExpr, arg_list) {
      sprintf(name_buffer, "name%i", name_index++);
      if (i != (alength-1)) {
        SymExpr* sExpr = toSymExpr(actualExpr);
        if (sExpr->symbol()->type != dtVoid) {
          ArgSymbol* newFormal = new ArgSymbol(INTENT_BLANK,
                                               name_buffer,
                                               sExpr->symbol()->type);
          parent_method->insertFormalAtTail(newFormal);
        }
      }
      ++i;
    }
  }
  if (retType != dtVoid) {
    VarSymbol *tmp = newTemp("_return_tmp_", retType);
    parent_method->insertAtTail(new DefExpr(tmp));
    parent_method->insertAtTail(new CallExpr(PRIM_RETURN, tmp));
  }
   Because this function type needs to be globally visible
   (because we don't know the modules it will be passed to), we put
   it at the highest scope
  theProgram->block->body.insertAtTail(new DefExpr(parent_method));
  normalize(parent_method);
  parent->methods.add(parent_method);
  return parent_method;
}
static FnSymbol * createAndInsertFunParentMethod ( CallExpr * call , AggregateType * parent , AList & arg_list , bool isFormal , Type * retType ) { { FnSymbol * rtGetter = new FnSymbol ( " " ) ; rtGetter -> addFlag ( FLAG_NO_IMPLICIT_COPY ) ; rtGetter -> addFlag ( FLAG_INLINE ) ; rtGetter -> addFlag ( FLAG_COMPILER_GENERATED ) ; rtGetter -> retTag = RET_TYPE ; rtGetter -> insertFormalAtTail ( new ArgSymbol ( INTENT_BLANK , " " , dtMethodToken ) ) ; ArgSymbol * _this = new ArgSymbol ( INTENT_BLANK , " " , parent ) ; _this -> addFlag ( FLAG_ARG_THIS ) ; rtGetter -> insertFormalAtTail ( _this ) ; rtGetter -> insertAtTail ( new CallExpr ( PRIM_RETURN , retType -> symbol ) ) ; DefExpr * def = new DefExpr ( rtGetter ) ; parent -> symbol -> defPoint -> insertBefore ( def ) ; normalize ( rtGetter ) ; parent -> methods . add ( rtGetter ) ; rtGetter -> setMethod ( true ) ; rtGetter -> addFlag ( FLAG_METHOD_PRIMARY ) ; rtGetter -> cname = astr ( " " , parent -> symbol -> cname , " " , rtGetter -> cname ) ; rtGetter -> addFlag ( FLAG_NO_PARENS ) ; rtGetter -> _this = _this ; } { FnSymbol * atGetter = new FnSymbol ( " " ) ; atGetter -> addFlag ( FLAG_NO_IMPLICIT_COPY ) ; atGetter -> addFlag ( FLAG_INLINE ) ; atGetter -> addFlag ( FLAG_COMPILER_GENERATED ) ; atGetter -> retTag = RET_TYPE ; atGetter -> insertFormalAtTail ( new ArgSymbol ( INTENT_BLANK , " " , dtMethodToken ) ) ; CallExpr * expr = new CallExpr ( PRIM_ACTUALS_LIST ) ; if ( isFormal ) { for_alist ( formalExpr , arg_list ) { DefExpr * dExp = toDefExpr ( formalExpr ) ; ArgSymbol * fArg = toArgSymbol ( dExp -> sym ) ; expr -> insertAtTail ( fArg -> type -> symbol ) ; } } else { for_alist ( actualExpr , arg_list ) { if ( actualExpr != arg_list . tail ) { SymExpr * sExpr = toSymExpr ( actualExpr ) ; expr -> insertAtTail ( sExpr -> symbol ( ) -> type -> symbol ) ; } } } ArgSymbol * _this = new ArgSymbol ( INTENT_BLANK , " " , parent ) ; _this -> addFlag ( FLAG_ARG_THIS ) ; atGetter -> insertFormalAtTail ( _this ) ; atGetter -> insertAtTail ( new CallExpr ( PRIM_RETURN , new CallExpr ( " " , expr ) ) ) ; DefExpr * def = new DefExpr ( atGetter ) ; parent -> symbol -> defPoint -> insertBefore ( def ) ; normalize ( atGetter ) ; parent -> methods . add ( atGetter ) ; atGetter -> setMethod ( true ) ; atGetter -> addFlag ( FLAG_METHOD_PRIMARY ) ; atGetter -> cname = astr ( " " , parent -> symbol -> cname , " " , atGetter -> cname ) ; atGetter -> addFlag ( FLAG_NO_PARENS ) ; atGetter -> _this = _this ; } FnSymbol * parent_method = new FnSymbol ( " " ) ; parent_method -> addFlag ( FLAG_FIRST_CLASS_FUNCTION_INVOCATION ) ; parent_method -> addFlag ( FLAG_COMPILER_GENERATED ) ; parent_method -> insertFormalAtTail ( new ArgSymbol ( INTENT_BLANK , " " , dtMethodToken ) ) ; parent_method -> setMethod ( true ) ; ArgSymbol * thisParentSymbol = new ArgSymbol ( INTENT_BLANK , " " , parent ) ; thisParentSymbol -> addFlag ( FLAG_ARG_THIS ) ; parent_method -> insertFormalAtTail ( thisParentSymbol ) ; parent_method -> _this = thisParentSymbol ; int i = 0 ; int alength = arg_list . length ; if ( isFormal ) { for_alist ( formalExpr , arg_list ) { DefExpr * dExp = toDefExpr ( formalExpr ) ; ArgSymbol * fArg = toArgSymbol ( dExp -> sym ) ; if ( fArg -> type != dtVoid ) { ArgSymbol * newFormal = new ArgSymbol ( INTENT_BLANK , fArg -> name , fArg -> type ) ; if ( fArg -> typeExpr ) newFormal -> typeExpr = fArg -> typeExpr -> copy ( ) ; parent_method -> insertFormalAtTail ( newFormal ) ; } } } else { char name_buffer [ 100 ] ; int name_index = 0 ; for_alist ( actualExpr , arg_list ) { sprintf ( name_buffer , " " , name_index ++ ) ; if ( i != ( alength - 1 ) ) { SymExpr * sExpr = toSymExpr ( actualExpr ) ; if ( sExpr -> symbol ( ) -> type != dtVoid ) { ArgSymbol * newFormal = new ArgSymbol ( INTENT_BLANK , name_buffer , sExpr -> symbol ( ) -> type ) ; parent_method -> insertFormalAtTail ( newFormal ) ; } } ++ i ; } } if ( retType != dtVoid ) { VarSymbol * tmp = newTemp ( " " , retType ) ; parent_method -> insertAtTail ( new DefExpr ( tmp ) ) ; parent_method -> insertAtTail ( new CallExpr ( PRIM_RETURN , tmp ) ) ; } theProgram -> block -> body . insertAtTail ( new DefExpr ( parent_method ) ) ; normalize ( parent_method ) ; parent -> methods . add ( parent_method ) ; return parent_method ; }
To mimic a function call, we create a .this method for the parent class.
To mimic a function call we create a . this method for the parent class .
// Add a "getter" method that returns the return type of the function // //   * The return type itself is not actually stored as a member variable // //   * A function that returns void will similarly cause a call to retType //     to return void, which is to say it doesn't return anything.  This is //     maybe not terribly intuitive to the user, but should be resolved //     when "void" becomes a fully-featured type. // Add a "getter" method that returns the tuple of argument types // for the function // We handle the arg list differently depending on if it's a list of // formal args or actual args // Because this function type needs to be globally visible // (because we don't know the modules it will be passed to), we put // it at the highest scope