2015-05-05 3 views
1

Для следующего глагола верхушки деревьев при разборе «3/14/01» (через t = Parser.parse('3/14/01') в irb), я получаю «TypeError: неправильный аргумент тип класса (ожидаемый модуль) ».Получение партиций даты из простого парсера с верхушками деревьев: неправильный тип аргумента Класс (ожидаемый модуль)

grammar SimpleDate 

    rule dateMDY 
     whitespace? month_part ('/'/'-') day_part (('/'/'-') year_part)? whitespace? <DateMDY> 
    end 

    rule month_part 
    (('1' [0-2])/('0'? [1-9])) <MonthLiteral> 
    end 

    rule day_part 
    (([12] [0-9])/('3' [0-1])/('0'? [1-9])) <DayLiteral> 
    end 

    rule year_part 
    (('1' '9')/('2' [01]))? [0-9] [0-9] <YearLiteral> # 1900 through 2199 (4 digit) 
    end 

    rule whitespace 
    [\s]+ 
    end 

end 

Первый, если я закомментируйте <MonthLiteral> и ссылки <DayLiteral> класса, все хорошо. Комментируя <DateMDY>, но оставляя эти объекты Literal, также выдает ошибку. Комментирование <YearLiteral>, похоже, не имеет значения (оно будет работать или не работать независимо) - это, по-видимому, указывает на то, что, поскольку первые два не являются терминальными, я не могу создавать для них элементы.

Очевидно, что я не понимаю, как Ruby (или treetop) создает экземпляры этих классов или поколения AST, которые объясняли бы, что происходит. Можете ли вы объяснить или указать мне на что-то, что может помочь мне понять, почему <MonthLiteral> или <DayLiteral> не могут быть созданы?

Второй, это может быть мостом слишком далеко, но то, что я действительно предпочел бы получить DateMDY объект с тремя атрибутами - месяц, день и год - так что я могу легко производить Ruby Time объект из метода to_time в DateMDY, но прямо сейчас я бы согласился на то, чтобы просто создать составляющие фигуры как объекты.

Так что я попытался оставить <DateMDY> как объект и закомментирована ссылки на <MonthLiteral>, <DayLiteral> и <YearLiteral>. Я видел, что полученный объект AST вернулся с .parse (t в моем первоначальном примере) имеет два открытых метода: :day_part и :month_part, но они кажутся нулевыми, когда я вызываю их (скажем, puts t.day_part), и нет метода :year_part, так что похоже, не помог мне.

Можно ли как-то сделать DateMDY в конечном итоге доступ к его составным частям?

FYI, код Parser Я использую довольно стандартный материал из учебников по верхушкам деревьев, а node_extensions.rb, который определяет классы объектов, также является тривиальным, но я тоже могу опубликовать их, если вам нужно их увидеть.

Спасибо! Richard

ответ

3

Сообщение об ошибке сообщает вам, что вы сделали неправильно. Есть только ограниченный набор мест, где вы можете использовать класс таким образом. Когда это разрешено, класс должен быть подклассом SyntaxNode. Обычно, однако, вы должны использовать модуль, который расширяет() ed в SyntaxNode, созданный внутренним правилом. Разница в случае YearLiteral заключается в том, что она не завершает последовательность в скобках так, как это делают литералы месяца и дня. Эта скобленная последовательность возвращает существующий SyntaxNode, который не может быть расширен() с другим классом, только с модулем, поэтому вы получаете TypeError.

Что касается вашего второго вопроса, то объект DateMDY, который вы хотите, почти наверняка не должен быть SyntaxNode, поскольку все SyntaxNodes сохраняют ссылки на все их дочерние синтаксические ноды и на входную строку - это внутренности парсера, о которых мы говорим. Вы действительно хотите выставить биты внутренних синтаксических парсеров во внешний мир?

Вместо этого вы должны организовать, чтобы соответствующий узел синтаксиса был посещен после завершения анализа, вызвав функцию, которая возвращает тип объекта домена, построенный с использованием подстрок, идентифицированных и сохраненных этими объектами парсера. Лучше всего добавить эти функции, чтобы перейти от своего верхнего правила, вместо того, чтобы пытаться пересечь дерево синтаксиса «извне».

Вы можете сделать это, добавив блок в свое верхнее правило, например (если у вас есть соответствующий класс DateMDY). Если у вас есть успешный дерево разбора, получить DateMDY по телефону «tree.result»:

rule dateMDY 
    whitespace? month_part ('/'/'-') day_part y:(('/'/'-') year_part)? whitespace? 
    { 
    def result 
     DateMDY.new(y.empty? ? nil : y.year_part.text_value.to_i, 
     month_part.text_value.to_i, 
     day_part.text_value.to_i) 
    end 
    } 
end 

Конечно, это уборщик добавить отдельные методы результата для year_part, month_part и day_part; это просто введение к тому, как добавить эти методы.

+0

спасибо, cliffordheath. Ваше объяснение YearLiteral имеет смысл. Повторите свой ответ на второй вопрос re DateMDY, теоретически, я согласен с вашим подходом, но у меня возникают проблемы с тем, как это реализовать. Я, вероятно, просто не нашел правильных примеров. Я могу больше взглянуть на примеры «в дикой природе», но есть ли публичный пример, который вы бы рекомендовали? Я уверен, что у меня просто ложное предположение о том, как это работает, и просто нужно, чтобы аха-момент, чтобы понять, как делать то, что вы предлагаете. Спасибо! – rdnewman

+0

Этот пример помогает, спасибо. Я немного поиграю с этим и помету ваш, как ответ, после того, как у меня будет шанс попробовать. Спасибо! – rdnewman

+0

всегда приветствуется! – cliffordheath

 Смежные вопросы

  • Нет связанных вопросов^_^