[Nitra] Маппинг сложного правила
От: pekabon  
Дата: 20.04.16 15:43
Оценка:
Привет

А есть возможность написать маппинг для такого правила

syntax refs_or_self = (ref_or_self (AS Name)?; ',')*;


без введения промежуточного фейкового правила?


Искал примеры по имеющимся грамматикам, нашел вот такое

    syntax QualifiedIdentifier  = QualifiedAlias? (QualifiedIdentifierPart; s "." s)+; 
    syntax QualifiedIdentifierPart = Reference (s QualifiedIdentifierPartTypeArguments)?;

я так понимаю, что промежуточное правило как раз чтобы удобнее маппить.
Но так делать не хочется (корячить грамматику ради маппинга).
Re: [Nitra] Маппинг сложного правила
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.04.16 19:15
Оценка: 12 (1)
Здравствуйте, pekabon, Вы писали:

P>А есть возможность написать маппинг для такого правила


У нас по маппингу Хардкейс специалист. Надеюсь он в ближайшее время откликнется и даст детальный ответ.

P>
syntax refs_or_self = (ref_or_self (AS Name)?; ',')*;

P>без введения промежуточного фейкового правила?

Откровенно говоря не знаю можно ли это выразить в текущем синтаксисе. Тут нужна помощь Хардкейса.

Пока он не ответил, могу предложить написать маппинг для этого случая вручную:

syntax refs_or_self = (ref_or_self (AS Name)?; ',')*;
...
map syntax Rules.refs_or_self -> PathReference* = AstUtils.Convert_refs_or_self(this);


В AstUtils.n:
public Convert_refs_or_self(refs_or_self : RulesParseTree.refs_or_self) : PathReference.IAstList
{
  if (refs_or_self.IsAmbiguous || refs_or_self.IsMissing)
    PathReference.AstList(refs_or_self.Location)
  else
  {
    def elems = refs_or_self.S.Item1.MapToArray(r => r.Item1.GetAst());
    PathReference.AstList(refs_or_self.Location, elems)
  }
}


"S" в "refs_or_self.S" — это имя автоматически вычисленное для списка. Честно говоря имя вычислилось криво. Правильное имя должно было бы быть "ref_or_selfs". Это надо будет поправить в будущем. Но пока — так. Его можно задать вручную:
syntax refs_or_self = Refs=(ref_or_self (AS Name)?; ',')*;

Но я так понимаю, что это тоже не желательно, так как код автогенеренный.

ЗЫ

То что вы преобразуете
ref_or_self (AS Name)?

в PathReference — это явно не верно. Для этого элемента надо создавать отдельный АСТ хранящий имя.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: [Nitra] Маппинг сложного правила
От: pekabon  
Дата: 25.04.16 16:44
Оценка:
Здравствуйте, VladD2, Вы писали:


VD>Но я так понимаю, что это тоже не желательно, так как код автогенеренный.


Мы сейчас правим сгенеренный один раз код руками. От периодической перегенерации отказались, т.к. исходная грамматика не особо поддерживается и уже out of date.

VD>То что вы преобразуете

VD>
VD>ref_or_self (AS Name)?
VD>

VD>в PathReference — это явно не верно. Для этого элемента надо создавать отдельный АСТ хранящий имя.

Попробовали сделать опциональный alias. Маппинг получился довольно корявый, как сделать лучше?

    syntax refs_or_self_part = ref_or_self (AS Name)?;

    ast RefOrSelfPathReference
    {
        PathReference : PathReference; 
        Alias : option[Name];
    } 

    map syntax Rules.refs_or_self_part -> RefOrSelfPathReference
    {
        Ref_or_self -> PathReference;
        
        Alias = if (NameOpt.HasValue)
                    ParsedValue(NameOpt.Value.Item2.Span, Some(NameOpt.Value.Item2.GetAst()))
                else
                    ParsedValue(NameOpt.Span, None());

    }
Re[3]: [Nitra] Маппинг сложного правила
От: VladD2 Российская Империя www.nemerle.org
Дата: 25.04.16 21:48
Оценка:
Здравствуйте, pekabon, Вы писали:

P>Попробовали сделать опциональный alias. Маппинг получился довольно корявый, как сделать лучше?


Лучше завести два АСТ-а и отматить на них (с помощью паттерн-матчинга) разные варианты.

Но в данном случае вопрос еще в том, как будет интерпретироваться этот псевдоним alias. Обычно для alias-а нужно заводить локальный символ в котором хранить ссылку на исходный объект. Для разного рода псевдонимов есть "declaration Alias" (поищи по этой подстроке в проекте Нитры).

Я не знаю в каком контексте псевдоним в Расте используется. Погляди, например, как сделаны псевдонимы в юсингах Шарпа (UsingAliasDirective).

Псевдоним должен использоваться в каком-то контексте и подменяться символом на который он ссылается когда на него ссылаются.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: [Nitra] Маппинг сложного правила
От: pekabon  
Дата: 26.04.16 08:22
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Но в данном случае вопрос еще в том, как будет интерпретироваться этот псевдоним alias. Обычно для alias-а нужно заводить локальный символ в котором хранить ссылку на исходный объект. Для разного рода псевдонимов есть "declaration Alias" (поищи по этой подстроке в проекте Нитры).

VD>Я не знаю в каком контексте псевдоним в Расте используется. Погляди, например, как сделаны псевдонимы в юсингах Шарпа (UsingAliasDirective).
VD>Псевдоним должен использоваться в каком-то контексте и подменяться символом на который он ссылается когда на него ссылаются.

Так и будет использоваться, это тот же юзинг, только немного сложнее. Например такое может быть

 use std::io::{self, Error, Result as IoResult};


В маппинге шарпа сделано через альтернативы и в синтаксисе, и в аст

    | Alias -> UsingAliasDirective
      {
        Name          -> Name;
        QualifiedName -> NamespaceOrTypeName;
      }


Смапить наш синтаксис на вариант пока не очень-то получается. Вот такое не компилируется

    syntax refs_or_self_part = ref_or_self (AS Name)?;

    abstract ast RefOrSelfPathReference
    {
    | Simple { PathReference : PathReference; }
    | Aliased { PathReference : PathReference; Alias : Name;}
    } 

    map syntax Rules.refs_or_self_part -> RefOrSelfPathReference
    {
        match (NameOpt)
        {
        | Some (name)     -> RefOrSelfPathReference.Aliased { Ref_or_self -> PathReference; name.Item2 -> Alias; }
        | None         -> RefOrSelfPathReference.Simple  { Ref_or_self -> PathReference; }
        }
    }

Ast.nitra(227,3): error : in argument #1 (item), needed a VisualRust.Grammar.RefOrSelfPathReference, got Nitra.Declarations.AstBase-: Nitra.Declarations.AstBase is not a subtype of VisualRust.Grammar.RefOrSelfPathReference [simple require]


При этом если сделать альтернативы одинаковыми — прокатывает

    match (NameOpt)
    {
    | Some (name) -> RefOrSelfPathReference.Simple  { Ref_or_self -> PathReference; }
    | None        -> RefOrSelfPathReference.Simple  { Ref_or_self -> PathReference; }
    }


Попытался уточнить тип везде где можно — не вышло, та же ошибка

    map syntax Rules.refs_or_self_part -> RefOrSelfPathReference
    {
        match (NameOpt)
        {
            | Some (name) -> RefOrSelfPathReference.Aliased { Ref_or_self -> PathReference; name.Item2 -> Alias; } : RefOrSelfPathReference
            | None          -> RefOrSelfPathReference.Simple  { Ref_or_self -> PathReference; } : RefOrSelfPathReference
        } : RefOrSelfPathReference
    }


Похоже на багу в реализации паттерн матчинга
Re[5]: [Nitra] Маппинг сложного правила
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.04.16 20:39
Оценка: 15 (2)
Здравствуйте, pekabon, Вы писали:

P>Похоже на багу в реализации паттерн матчинга


Да, наша недоработка. RefOrSelfPathReference преобразуется в интерфейс, а компилятор Немерла недоперает, что этот интерфейс является общим типом для классов в которые преобразуются RefOrSelfPathReference.Aliased и RefOrSelfPathReference.Simple.

Постараемся исправить в ближайшее время. Пока могу предложить обходной вариант:
map syntax Rules.refs_or_self_part -> RefOrSelfPathReference
{
  match (NameOpt)
  {
    | Some((_, name))  ->
      let res : RefOrSelfPathReference = RefOrSelfPathReference.Aliased { Ref_or_self -> PathReference; name -> Alias; } in
      res

    | None             -> 
      let res : RefOrSelfPathReference = RefOrSelfPathReference.Simple  { Ref_or_self -> PathReference; } in
      res
  }
}


у let есть возможность задать тип явно. Так что два let можно использовать как тайп-хинт. Напрямую тайп-хинты пока не поддерживаются.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Отредактировано 26.04.2016 20:40 VladD2 . Предыдущая версия .
Re[5]: [Nitra] Маппинг сложного правила
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.04.16 22:04
Оценка: 15 (1)
Здравствуйте, pekabon, Вы писали:

P>Похоже на багу в реализации паттерн матчинга


Починили. Теперь работает вариант:
map syntax Rules.refs_or_self_part -> RefOrSelfPathReference
{
  match (NameOpt)
  {
    | Some((_, name)) -> RefOrSelfPathReference.Aliased { Ref_or_self -> PathReference; name -> Alias; }
    | None            -> RefOrSelfPathReference.Simple  { Ref_or_self -> PathReference; }
  }
}


Только учти, что RefOrSelfPathReference.Aliased тебе нужно сделать declaration-ом, так как псевдоним вводит новый локальный символ.

Посмотри внимательно как в DotNetLang сделана поддержка using-alias-ов (UsingDirective.nitra, NamespaceMember.nitra и Namespace.nitra). Особенно на зависимое свойство UsingAliasesScope.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Отредактировано 26.04.2016 22:05 VladD2 . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.