Помогите с макросом
От: kaa_t Россия  
Дата: 06.10.17 02:25
Оценка:
Доброго дня

Написал такой макрос. Все работает если в методах нет return или yield.
Как узнать что в методе используется ключевое слово yield?
Как побороть ошибку error : goto (block return?) is not allowed inside expressions

[MacroUsage(MacroPhase.WithTypedMembers, MacroTargets.Class)]
  macro Flag(typeBuilder : TypeBuilder, params args : array[PExpr])
  {
    FlagImpl.DoTransform(Macros.ImplicitCTX(), typeBuilder, args)
  }
  
  
  
  module FlagImpl
  {
    [ParseParameters]
    class Parameters
    {
      public Name:PExpr;
      public Debug:bool;
      public Property:bool;
      public Include:list[PExpr];
    }
    
    public mcatch DoTransform(typer : Typer, typeBuilder : TypeBuilder, args : array[PExpr]) : void
    {
      Macros.DefineCTX(typer);
      // TODO: Add implementation here.
      _ = typeBuilder; _ = args;
      def context = MacroContext(typer,typeBuilder);
      def par = Parameters(args);
      when(par.Debug) context.Debug =  true;
      
      def name = 
              switch{
                | par.Property => Macros.NewSymbol("flag").ToStr();
                | par.Name != null => par.Name.ToStr()
                | _ => "_flag"
              }
      
      
      <[decl: mutable $(name:usesite):bool = false ]> |> context.DeclareMember;
      
      when(par.Property) {
        def pname = if(par.Name == null) "Flag" else par.Name.ToStr();
        <[decl: public $(pname:usesite):bool { get { $(name:usesite)  } } ]> |> context.DeclareMember;
      }
      
      foreach(m is MethodBuilder in typeBuilder.GetMethods()) 
      {
        when(!m.IsPublic) continue;
        when(m.IsConstructor) continue;
        if( m.ReturnType.TryRequire(<[ttype:void]>) )
        {
          m.Body = locate(m.Body.Location)
          <[
          {
            try { $(name:usesite) = true; $(m.Body)   } finally { $(name:usesite) = false;   }
          }
          ]>
        }
        else
        {
          m.Body = locate(m.Body.Location)
          <[
          {
            mutable result;
            try { $(name:usesite) = true; result = $(m.Body)   } finally { $(name:usesite) = false;   }
            result;
          }
          ]>
        }
      }
    }
  }
Re: Помогите с макросом
От: VladD2 Российская Империя www.nemerle.org
Дата: 06.10.17 07:47
Оценка: 6 (1)
Здравствуйте, kaa_t, Вы писали:

_>Написал такой макрос. Все работает если в методах нет return или yield.

_>Как узнать что в методе используется ключевое слово yield?

Можно найти yield в коде метода с помощью класса Nemerle.Compiler.ExprWalker:
foreach(m is MethodBuilder in typeBuilder.GetMethods())
{
  mutable hasYield = false;
  def walker = ExprWalker();
  def walk(info : ExprWalkInfo) : void
  {
    when (info.Node is PExpr.MacroCall(name=Name(Id="yield")))
    {
      hasYield = true;
      info.Stop();
    }
  }
  walker.Walk(m.Body, walk);

  when (hasYield)
    Message.Hint(m.Location, $"The method '$(m.Name)' call 'yield' macro.");
}


_>Как побороть ошибку error : goto (block return?) is not allowed inside expressions


Эта ошибка означает, что где-то есть нелокальный выход из функции или выражения. Например, если написать break внутри локальной функции находящейся в цикле, то может появиться такое сообщение. Или если написать return внутри выражения.

Часто это бывает связано с некорректной генерацией кода.

В приведенном фрагменте вроде ничего такого нет. Но в нем есть применение каких-то макросов. Возможно ошибка в них.

Вот в этом нет смысла:
_>
_>          <[
_>          {
_>            mutable result;
_>            try { $(name:usesite) = true; result = $(m.Body)   } finally { $(name:usesite) = false;   }
_>            result;
_>          }
_>          ]>
_>


блок try и так возвращает значение. Можно выбросить if и всегда возвращать первый вариант кода.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.