2017-01-18 38 views
3

Мне было любопытно, можно ли вставлять вещи в дерево матча, фактически ничего. Я не пытаюсь решить проблему.Могу ли я вставлять именованные захваты в дерево совпадений, фактически ничего не согласуя?

В этом примере у меня есть токен market, который проверяет, что его совпадение является ключом в хэше. Затем я попытался как-то вставить значение этого хэша в дерево соответствий. Я решил, что у меня может быть токен, который всегда совпадает, long_market_string, а затем заглянуть в дерево, чтобы увидеть, что соответствовало market.

grammar OrderNumber::Grammar { 
    token TOP { 
     <channel> <product> <market> <long_market_string> '/' <revision> 
     } 

    token channel { <[ M F P ]> } 
    token product { <[ 0..9 A..Z ]> ** 4 } 

    token market  { 
     (<[ A..Z ]>** 1..2) <?{ %Market_Shortcode{$0}:exists }> 
     } 

    # this should figure out what market matched 
    # I don't particularly care how this happens as long as 
    # I can insert this into the match tree 
    token long_market_string { <?> } 

    token revision { <[ A..C ]> } 
    } 

Есть ли какой-нибудь способ, чтобы возиться с Match дерева, как она создается?

я мог бы сделать что-то, что инвертирует вещи:

grammar AppleOrderNumber::Grammar { 
    token TOP { 
     <channel> <product> <long_market_string> '/' <revision> 
     } 

    token channel { <[ M F P ]> } 
    token product { <[ 0..9 A..Z ]> ** 4 } 

    token market  { 
     (<[ A..Z ]>** 1..2) <?{ %Market_Shortcode{$0}:exists }> 
     } 
    token long_market_string { <market> } 
    token revision { <[ A..C ]> } 
    } 

Но, который обрабатывает этот случай. Меня больше интересует вставка произвольного количества вещей.

ответ

1

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

Это не указано, и в настоящее время это не просто.
(у меня есть только смутное представление о том, где начать искать в исходном коде, чтобы понять это)


То, что вы можете легко сделать, это добавить к .made/.ast результата
(.made и .ast являются синонимами)

$/ = grammar { 
    token TOP { 
    .* 
    { 
     make 'World' 
    } 
    } 
}.parse('Hello'); 

say "$/ $/.made()"; # Hello World 

Он даже не должен быть внутри грамматики

'asdf' ~~ /{make 42}/; 
say $/;  # 「」 
say $/.made # 42 

Большая часть времени вы будете использовать класс Actions для такого рода вещи

grammar example-grammar { 
    token TOP { 
    [ <number> | <word> ]+ % \s* 
    } 
    token word { 
    <.alpha>+ 
    } 
    token number { 
    \d+ 
    { make +$/ } 
    } 
} 

class example-actions { 
    method TOP ($/) { make $/.pairs.map:{ .key => .value».made} } 
    method number ($/) { #`(already done in grammar, so this could be removed) } 
    method word ($/) { make ~$/ } 
} 

.say for example-grammar.parse(
    'Hello 123 World', 
    :actions(example-actions) 
).made».perl 

# :number([123]) 
# :word(["Hello", "World"]) 
+0

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

+0

@briandfoy Int - также неизменный объект. Когда я сказал, что токен - это тип метода, я имею в виду, что он наследует метод, и добавляет кучу вещей. Если вы делаете эту кучу вещей самостоятельно в обычном методе, вы можете делать абсолютно все, что может сделать токен. Я не планирую потратить неделю или больше на исходный код, чтобы сделать то, что почти никто не должен делать. Я пытался сделать это одно и то же несколько раз, прежде чем вы спросили, и не думал, что это стоит того времени, потратив на это часы. –

+0

Хорошо, но я уже знаю это и не обсуждал это. Вы сказали, что попробовали одно и то же (я предполагаю, что вы не могли это сделать), но это также звучит так, будто вы пытаетесь убедить меня, что это тривиально делать самостоятельно. Там есть смешанные сообщения. –

0

Это звучит, как вы хотите, чтобы разрушить дерево матча в делать что-то дерево матча на самом деле не должно делать. Дерево совпадений отслеживает, какие подстроки были сопоставлены, где во входной строке, а не произвольные данные, созданные парсером. Если вы хотите отслеживать произвольные данные, что случилось с деревом AST?

Несомненно, в некотором смысле дерево AST должно отражать дерево разбора, поскольку оно построено снизу вверх, когда методы совпадения завершаются успешно. Но сам АСТ, в смысле «объекта, привязанного к любому узлу», не ограничен. Рассмотрим, например:

grammar G { 
    token TOP { <foo> <bar> {make "TOP is: " ~ $<foo> ~ $<bar>} } 
    token foo { foo {make "foo"} } 
    token bar { bar {make "bar"} } 
} 
G.parse("foobar"); 

$/.made Здесь будет просто строка «TOP является: Foobar» в то время как дерево матч имеет дочерние узлы с компонентами, которые были использованы для построения AST верхнего уровня. Если затем вернуться к примеру, мы можем сделать это:

grammar G { 
    my %Market_Shortcode = :AA('Double A'); 
    token TOP { 
     <channel> <product> <market> 
     {} # Force the computation of the $/ object. Note that this will also terminate LTM here. 
     <long_market_string(~$<market>)> '/' <revision> 
     } 

    token channel { <[ M F P ]> } 
    token product { <[ 0..9 A..Z ]> ** 4 } 

    token market  { 
     (<[ A..Z ]>** 1..2) <?{ %Market_Shortcode{$0}:exists }> 
     } 

    token long_market_string($shortcode) { <?> { say 'c='~$shortcode; make %Market_Shortcode{$shortcode} } } 

    token revision { <[ A..C ]> } 
    } 

G.parse('M0000AA/A'); 

$<long_market_string>.ast теперь будет «Double A».Конечно, я бы обойду token long_market_name и просто сделаю АСТ token market тем, что находится в %Market_Shortcode (или объект Market с коротким и длинным именем, если вы хотите отследить оба одновременно).

Менее тривиальный пример такого рода вещей был бы чем-то вроде грамматики Python. Поскольку структура уровня блока Python основана на линии, ваша грамматика (и, соответственно, дерево соответствия) должна каким-то образом отразить это. Но вы можете также объединить несколько простых операторов в одну строку, разделив их на полуколоны. Теперь вы, вероятно, захотите, чтобы AST блока представлял собой список операторов, тогда как AST одной строки сам может быть списком нескольких операторов. Таким образом, вы должны построить AST блока (например) flatmap, соединяя список строк (или что-то вдоль этих строк, в зависимости от того, как вы представляете операторы блоков, такие как if и while).

Теперь, если вы действительно, действительно, действительно хотите делать неприятные вещи в дереве соответствий. Я уверен, что это можно сделать, конечно. Вам придется реализовать код разбора самостоятельно с помощью method long_market_name, API, для которого недокументирован и является внутренним, и, вероятно, будет включать, по крайней мере, некоторое падение в nqp :: ops. Материал, на который указывает here, вероятно, будет полезен. Другие соответствующие файлы: src/core/{Match,Cursor}.pm в репо Rakudo. Обратите также внимание на то, что строка совпадений вычисляется путем извлечения согласованной подстроки из входной строки, поэтому, если вы хотите, чтобы она была полезной, вы должны подклассировать Match.

+0

Дерево AST - это то, что я пытаюсь подорвать. Но, действительно, нет АСТ. Существует дерево объектов соответствия, у которых есть ключ, называемый «ast», который не связан напрямую. AST должен иметь ту же структуру, что и дерево соответствия. –

+0

«АСТ вынужден иметь ту же структуру, что и дерево матча», а? –

+0

АСТ живет в объектах совпадения. –