File Coverage

blib/lib/MarpaX/Languages/M4/Impl/Parser.pm
Criterion Covered Total %
statement 331 350 94.5
branch 96 140 68.5
condition 33 54 61.1
subroutine 29 31 93.5
pod 0 1 0.0
total 489 576 84.9


line stmt bran cond sub pod time code
1 1     1   6 use Moops;
  1         2  
  1         5  
2              
3             # PODNAME: MarpaX::Languages::M4::Impl::Parser
4              
5             # ABSTRACT: M4 Marpa parser
6              
7             #
8             # Expose only the base implementation of parse() method
9             # required by MarpaX::Languages::M4::Role::Parser
10             #
11 1     1   84680 class MarpaX::Languages::M4::Impl::Parser {
  1     1   25  
  1         7  
  1         2  
  1         54  
  1         271  
  1         1433  
  1         4  
  1         1240  
  1         2  
  1         7  
  1         62  
  1         6  
  1         44  
  1         5  
  1         1  
  1         90  
  1         34  
  1         7  
  1         2  
  1         9  
  1         3800  
  1         2  
  1         7  
  1         633  
  1         3139  
  1         4  
  1         154  
  1         2  
  1         6  
  1         339  
  1         5874  
  1         38  
  1         593  
  1         2107  
  1         5  
  1         1035  
  1         2110  
  1         8  
  1         104764  
  1         3  
  1         5  
  1         2  
  1         21  
  1         4  
  1         2  
  1         41  
  1         5  
  1         2  
  1         97  
  1         6116  
  0         0  
12 1     1   395 use MarpaX::Languages::M4::Impl::Parser::Actions;
  1         3  
  1         10  
13 1     1   51 use MarpaX::Languages::M4::Type::Macro -all;
  1         48  
  1         7  
14 1     1   833 use MarpaX::Languages::M4::Impl::Value;
  1         1  
  1         5  
15 1     1   405 use Marpa::R2; # 2.103_004;
  1         105589  
  1         20  
16 1     1   48 use Scalar::Util qw/readonly/;
  1         1  
  1         98  
17 1     1   7 use Types::Common::Numeric -all;
  1         2  
  1         11  
18             #
19             # --nesting_limit (SHOULD) take care of that
20             #
21 1     1   5550 no warnings 'recursion';
  1         2  
  1         283  
22              
23 1         12 our $VERSION = '0.020'; # VERSION
24              
25 1         2 our $AUTHORITY = 'cpan:JDDPAUSE'; # AUTHORITY
26              
27 1         3 our $BASE_GRAMMAR = q{
28             inaccessible is ok by default
29             :default ::= action => ::first
30             lexeme default = latm => 1
31              
32             #
33             # Note: this part of the grammar is giving ambiguity
34             # but we do not mind because the effect is always
35             # the same: global concatenatation
36             #
37             argumentsGroup ::= tokens action => createArgumentsGroup rank => 1
38             | argumentsGroup LPAREN argumentsGroup RPAREN argumentsGroup action => mergeArgumentsGroup
39              
40             arguments ::= argumentsGroup action => firstArg
41             | arguments (COMMA) argumentsGroup action => nextArg
42              
43             tokens ::= token* action => create
44             event '^token' = predicted <token> # This event is to force $r->read() to not advance its location
45             event 'token$' = completed <token>
46             token ::= WORD
47             | macro
48             | QUOTEDSTRING
49             | CHARACTER
50             | COMMENT
51             | ANYTHING
52              
53             macro ::= MACRO # Never lexeme_read'ed
54             | MACRO_ARGS macroArguments # Ditto
55              
56             event 'macroArguments$' = completed <macroArguments>
57             macroArguments ::= (LPAREN) arguments (RPAREN)
58             macroArguments ::= (NOPARAM) action => fakeOneVoidParam
59              
60             _ANYTHING ~ [\s\S]
61             _NOTHING ~ [^\s\S]
62             WORD ~ _NOTHING
63             MACRO ~ _NOTHING
64             MACRO_ARGS ~ _NOTHING
65             QUOTEDSTRING ~ _NOTHING
66             CHARACTER ~ _NOTHING
67             COMMENT ~ _NOTHING
68             #
69             # ANYTHING will automatically eat a character each time we resume the SLIF: we
70             # do not want this to happen
71             #
72             :lexeme ~ <ANYTHING> pause => before event => '^ANYTHING'
73             ANYTHING ~ _ANYTHING
74              
75             _WS ~ [\s]
76             _WS_any ~ _WS*
77              
78             :lexeme ~ <LPAREN> priority => 1 pause => before event => '^LPAREN'
79             LPAREN ~ '(' _WS_any
80              
81             :lexeme ~ <RPAREN> priority => 1 pause => before event => '^RPAREN'
82             RPAREN ~ ')'
83              
84             :lexeme ~ <NOPARAM> priority => 1
85             NOPARAM ~ '(' _WS_any ')'
86              
87             #
88             # Quote from the spec (M4 POSIX):
89             # If a macro name is followed by a <left-parenthesis>, its arguments are the <comma>-separated tokens
90             # between the <left-parenthesis> and the matching <right-parenthesis>. Unquoted white-space characters
91             # preceding each argument shall be ignored. All other characters, including trailing white-space characters,
92             # are retained.
93             # <comma> characters enclosed between <left-parenthesis> and <right-parenthesis> characters do not delimit arguments.
94              
95             :lexeme ~ <COMMA> priority => 1
96             COMMA ~ ',' _WS_any
97             };
98              
99 1         2 our $BYTOKEN_G = do {
100             my $g = Marpa::R2::Scanless::G->new(
101 1         3 { source => \do {":start ::= tokens\n$BASE_GRAMMAR"}
  1         31  
102             }
103             );
104             };
105 1         186045 our $BYMACROARGUMENTS_G = do {
106             my $g = Marpa::R2::Scanless::G->new(
107 1         4 { source => \do {":start ::= macroArguments\n$BASE_GRAMMAR"}
  1         27  
108             }
109             );
110             };
111              
112 0         0 BEGIN {
113             #
114             # Marpa internal optimisation: we do not want the closures to be rechecked every time
115             # we call $r->value(). This is a static information, although determined at run-time
116             # the first time $r->value() is called on a recognizer.
117             #
118 1     1   7 no warnings 'redefine';
  1     0   2  
  1         462  
119              
120             sub Marpa::R2::Recognizer::registrations {
121 2024     2024 0 4787 my $recce = shift;
122 2024 100       7402 if (@_) {
123 2022         6076 my $hash = shift;
124 2022 50 33     19813 if (! defined($hash) ||
      33        
125             ref($hash) ne 'HASH' ||
126 14154         40026 grep {! exists($hash->{$_})} qw/
127             NULL_VALUES
128             REGISTRATIONS
129             CLOSURE_BY_SYMBOL_ID
130             CLOSURE_BY_RULE_ID
131             RESOLVE_PACKAGE
132             RESOLVE_PACKAGE_SOURCE
133             PER_PARSE_CONSTRUCTOR
134             /) {
135             Marpa::R2::exception(
136             "Attempt to reuse registrations failed:\n",
137             " Registration data is not a hash containing all necessary keys:\n",
138 0 0       0 " Got : " . ((ref($hash) eq 'HASH') ? join(', ', sort keys %{$hash}) : '') . "\n",
  0         0  
139             " Want: CLOSURE_BY_RULE_ID, CLOSURE_BY_SYMBOL_ID, NULL_VALUES, PER_PARSE_CONSTRUCTOR, REGISTRATIONS, RESOLVE_PACKAGE, RESOLVE_PACKAGE_SOURCE\n"
140             );
141             }
142 2022         7598 $recce->[Marpa::R2::Internal::Recognizer::NULL_VALUES] = $hash->{NULL_VALUES};
143 2022         6521 $recce->[Marpa::R2::Internal::Recognizer::REGISTRATIONS] = $hash->{REGISTRATIONS};
144 2022         5785 $recce->[Marpa::R2::Internal::Recognizer::CLOSURE_BY_SYMBOL_ID] = $hash->{CLOSURE_BY_SYMBOL_ID};
145 2022         4816 $recce->[Marpa::R2::Internal::Recognizer::CLOSURE_BY_RULE_ID] = $hash->{CLOSURE_BY_RULE_ID};
146 2022         5864 $recce->[Marpa::R2::Internal::Recognizer::RESOLVE_PACKAGE] = $hash->{RESOLVE_PACKAGE};
147 2022         7403 $recce->[Marpa::R2::Internal::Recognizer::RESOLVE_PACKAGE_SOURCE] = $hash->{RESOLVE_PACKAGE_SOURCE};
148 2022         5577 $recce->[Marpa::R2::Internal::Recognizer::PER_PARSE_CONSTRUCTOR] = $hash->{PER_PARSE_CONSTRUCTOR};
149             }
150             return {
151 2024         20455 NULL_VALUES => $recce->[Marpa::R2::Internal::Recognizer::NULL_VALUES],
152             REGISTRATIONS => $recce->[Marpa::R2::Internal::Recognizer::REGISTRATIONS],
153             CLOSURE_BY_SYMBOL_ID => $recce->[Marpa::R2::Internal::Recognizer::CLOSURE_BY_SYMBOL_ID],
154             CLOSURE_BY_RULE_ID => $recce->[Marpa::R2::Internal::Recognizer::CLOSURE_BY_RULE_ID],
155             RESOLVE_PACKAGE => $recce->[Marpa::R2::Internal::Recognizer::RESOLVE_PACKAGE],
156             RESOLVE_PACKAGE_SOURCE => $recce->[Marpa::R2::Internal::Recognizer::RESOLVE_PACKAGE_SOURCE],
157             PER_PARSE_CONSTRUCTOR => $recce->[Marpa::R2::Internal::Recognizer::PER_PARSE_CONSTRUCTOR]
158             };
159             } ## end sub registrations
160              
161             sub Marpa::R2::Scanless::R::registrations {
162 2024     2024   5243 my $slr = shift;
163 2024         5096 my $thick_g1_recce =
164             $slr->[Marpa::R2::Internal::Scanless::R::THICK_G1_RECCE];
165 2024         12104 return $thick_g1_recce->registrations(@_);
166             } ## end sub Marpa::R2::Scanless::R::registrations
167              
168             }
169              
170 1         64752 has _parse_level => (
171             is => 'rwp',
172             isa => PositiveOrZeroInt,
173              
174             # trigger => 1,
175             default => 0
176             );
177              
178 1 0   1   2776 method _trigger__parse_level (PositiveOrZeroInt $parse_level, @rest) {
  1 0   1   2  
  1 0   0   136  
  1 0       6  
  1 0       3  
  1 0       142  
  1         1904  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
179             #
180             # GNU testing of nesting_limit is another implementation, this
181             # has no meaning for us. So, even if supported, this option does
182             # nothing: the trigger is NOT enabled.
183             #
184 0         0 my $nesting_limit = $self->impl_nestingLimit;
185 0 0 0     0 if ( $nesting_limit > 0 && $parse_level > $nesting_limit ) {
186 0         0 $self->impl_raiseException(
187             sprintf( 'Nesting limit of %d exceeded', $nesting_limit ) );
188             }
189             }
190              
191 1 50   1   2147 method parser_parse (Str $input --> Str) {
  1 50   1   2  
  1 50   164   130  
  1 50       6  
  1 50       1  
  1         84  
  1         230  
  164         2345  
  164         768  
  164         638  
  164         655  
  164         488  
  164         734  
  164         298  
192             #
193             # We will modify the buffer in-place, therefore we want to
194             # have OUR version of the input.
195             # In addition, this will solve the eventual problem of $input
196             # being a read-only variable
197             #
198 164         489 my $work = $input;
199 164         3179 return $self->_parseByTokens( \$work );
200             }
201              
202             #
203             # By token => ConsumerOf['MarpaX::Languages::M4::Role::Value by default']
204             # By arguments => ArrayRef[ConsumerOf['MarpaX::Languages::M4::Role::Value']]
205             #
206 1 50 33 1   18751 method _parseByGrammar (Ref['SCALAR'] $inputRef, PositiveOrZeroInt $pos, InstanceOf['Marpa::R2::Scanless::G'] $g, Undef|M4Macro $macro? --> Undef|Dict[pos => PositiveOrZeroInt, value => ConsumerOf['MarpaX::Languages::M4::Role::Value']]) {
  1 50 33 1   3  
  1 50   1   143  
  1 50   1   6  
  1 50   1   2  
  1 50   2018   122  
  1 50       6  
  1 50       2  
  1 50       93  
  1 50       6  
  1 50       2  
  1 50       112  
  1 100       6  
  1 50       2  
  1 100       2120  
  1         2161  
  2018         22791  
  2018         7336  
  2018         6466  
  2018         6526  
  2018         6090  
  2018         3333  
  2018         16548  
  2018         6649  
  2018         7147  
  2018         3508  
  2018         8154  
  2018         6882  
  2018         7826  
  2018         4251  
  2018         11834  
  2018         6992  
  2018         5897  
  1854         3497  
  1854         7397  
  2018         40086  
207              
208 2018         3461 my $maxPos = length( ${$inputRef} ) - 1;
  2018         6029  
209             #
210             # Protect the case of empty string.
211             # This is affecting all parsing levels.
212             #
213 2018 100       7451 if ( $pos > $maxPos ) {
214 1         18 return;
215             }
216             #
217             # Get the lexemes ordering
218             #
219 2017         10664 my @lexemeNames = $self->parser_tokensPriority();
220             #
221             # In the context of a macroArguments, unquoted parenthesis
222             # have higher priorities over everything, except quoted string
223             # and comment.
224             #
225 2017 100       118678 if ( $g == $BYMACROARGUMENTS_G ) {
226 1854         9977 unshift( @lexemeNames, 'NOPARAM', 'LPAREN', 'RPAREN', 'COMMA' );
227             }
228              
229 2017         36859 my $value = MarpaX::Languages::M4::Impl::Value->new();
230 2017         75851 my %rc = ( pos => $pos, value => $value );
231              
232             #
233             # Instanciate and start recognizer
234             #
235 2017         22252 my $r = Marpa::R2::Scanless::R->new(
236             { grammar => $g,
237             semantics_package => 'MarpaX::Languages::M4::Impl::Parser::Actions',
238             exhaustion => 'event',
239              
240             # trace_terminals => 1,
241             # trace_values => 1
242             }
243             );
244             #
245             # $prevPos is used only for logging
246             #
247 2017         777493 my $prevPos = $rc{pos} = $pos;
248             #
249             # The stream itself is of no importance.
250             # We use Marpa to drive the context, nothing more.
251             # But is it NOT a hasard that I use the constant '(':
252             # when doing a recursive call using
253             # the macroByarguments grammar, Marpa will expect this
254             # character at the first read, EVEN
255             # if we paused before it.
256             #
257 2017         12459 $r->read( \'(' );
258              
259             again:
260 4440         260787 while ( $rc{pos} <= $maxPos ) {
261              
262             # $self->logger_debug( '[%d..%d/%d] 20 first characters: %s',
263             # $rc{pos}, $rc{pos}, $maxPos,
264             # substr( ${$inputRef}, $rc{pos}, 20 ) );
265              
266 23409         36715 my %expected = map { $_ => 1 } @{ $r->terminals_expected };
  186963         2701285  
  23409         67813  
267              
268             # $self->logger_debug(
269             # '[%d..%d/%d] Expected terminals: %s',
270             # $rc{pos}, $rc{pos}, $maxPos,
271             # [ keys %expected ]
272             # );
273              
274 23409 100       110311 if ( $r->exhausted ) {
275              
276             # $self->logger_debug( '[%d..%d/%d] Parse is exhausted',
277             # $rc{pos}, $rc{pos}, $maxPos );
278              
279 1823         20536 last;
280             }
281              
282 21586         290677 my $lexemeValue;
283             my $lexemeLength;
284 21586         0 my $lexeme;
285              
286 21586         0 my $QuotedstringValue;
287 21586         0 my $QuotedstringLength;
288 21586         59847 my $isQuotedString = false;
289              
290 21586         78175 my $CommentValue;
291             my $CommentLength;
292 21586         47713 my $isComment = false;
293              
294 21586         73100 my $canCollectArguments = true;
295 21586 100       92733 if ( $g == $BYMACROARGUMENTS_G ) {
296 16948         36012 my $blockOk = false;
297             try {
298             $isQuotedString
299 16948         383055 = $self->parser_isQuotedstring( ${$inputRef},
300             $rc{pos},
301 16948     16948   425256 $maxPos, \$QuotedstringValue, \$QuotedstringLength );
302             $isComment
303 16948         277833 = $self->parser_isComment( ${$inputRef}, $rc{pos},
304 16948         397861 $maxPos, \$CommentValue, \$CommentLength );
305 16948   100     415050 $canCollectArguments = !$isQuotedString && !$isComment;
306 16948         39455 $blockOk = true;
307 16948         144529 };
308 16948 50       275595 if ( !$blockOk ) {
309 0         0 goto return_error;
310             }
311             }
312              
313 21586         52794 foreach (@lexemeNames) {
314 112029 100       291701 if ( $_ eq 'NOPARAM' ) {
    100          
    100          
    100          
315 16948 100 66     48728 if ( exists( $expected{NOPARAM} )
316             && $canCollectArguments )
317             {
318 1854         3751 pos( ${$inputRef} ) = $rc{pos};
  1854         7676  
319 1854 100       4042 if ( ${$inputRef} =~ /\G\(\s*\)/s ) {
  1854         12876  
320 15         48 $lexeme = 'NOPARAM';
321 15         28 $lexemeValue = substr( ${$inputRef}, $-[0],
  15         139  
322             $+[0] - $-[0] );
323 15         68 $lexemeLength = $+[0] - $-[0];
324 15         41 last;
325             }
326             }
327             }
328             elsif ( $_ eq 'LPAREN' ) {
329 16933 100 66     57970 if ( exists( $expected{LPAREN} )
      66        
      66        
330             && $canCollectArguments
331 12860         22978 && do { pos( ${$inputRef} ) = $rc{pos}; 1 }
  12860         33710  
  12860         41919  
332 12860         54885 && ${$inputRef} =~ /\G\(\s*/
333             )
334             {
335 1870         6949 $lexeme = 'LPAREN';
336 1870         13748 $lexemeLength = $+[0] - $-[0];
337             $lexemeValue
338 1870         4382 = substr( ${$inputRef}, $-[0], $lexemeLength );
  1870         8964  
339 1870         4408 last;
340             }
341             }
342             elsif ( $_ eq 'RPAREN' ) {
343 15063 100 66     54385 if ( exists( $expected{RPAREN} )
      100        
344             && $canCollectArguments
345 10990         41791 && substr( ${$inputRef}, $rc{pos}, 1 ) eq ')' )
346             {
347 1869         4191 $lexeme = 'RPAREN';
348 1869         3678 $lexemeValue = ')';
349 1869         3824 $lexemeLength = 1;
350 1869         4746 last;
351             }
352             }
353             elsif ( $_ eq 'COMMA' ) {
354 13194 100 100     47366 if ( exists( $expected{COMMA} ) && $canCollectArguments )
355             {
356 9025         13628 pos( ${$inputRef} ) = $rc{pos};
  9025         18400  
357 9025 100       15837 if ( ${$inputRef} =~ /\G,\s*/s ) {
  9025         31767  
358 2666         5072 $lexeme = 'COMMA';
359 2666         4817 $lexemeValue = substr( ${$inputRef}, $-[0],
  2666         26561  
360             $+[0] - $-[0] );
361 2666         16282 $lexemeLength = $+[0] - $-[0];
362 2666         5869 last;
363             }
364             }
365             }
366             else {
367 49891 100 100     198305 if ( $g == $BYMACROARGUMENTS_G && $_ eq 'QUOTEDSTRING' ) {
    100 100        
368             #
369             # Already done in the context of macro arguments grammar
370             #
371 9654 100       23061 if ($isQuotedString) {
372 4068         6606 $lexeme = $_;
373 4068         7155 $lexemeValue = $QuotedstringValue;
374 4068         5871 $lexemeLength = $QuotedstringLength;
375 4068         6631 last;
376             }
377             }
378             elsif ( $g == $BYMACROARGUMENTS_G && $_ eq 'COMMENT' ) {
379             #
380             # Already done in the context of macro arguments grammar
381             #
382 10528 100       24353 if ($isComment) {
383 5         11 $lexeme = $_;
384 5         13 $lexemeValue = $CommentValue;
385 5         11 $lexemeLength = $CommentLength;
386 5         15 last;
387             }
388             }
389             else {
390             #
391             # QUOTEDSTRING is not already done if not
392             # in the context of macro arguments grammar
393             # Ditto for COMMENT.
394             #
395 29709         92690 my $method = 'parser_is' . ucfirst( lc($_) );
396 29709         63170 my $blockOk = false;
397 29709         98169 my $isToken;
398             try {
399 29709         639274 $isToken = $self->$method( ${$inputRef}, $rc{pos},
400 29709     29709   704686 $maxPos, \$lexemeValue, \$lexemeLength );
401 29705         743871 $blockOk = true;
402 29709         170686 };
403 29709 100       444680 if ( !$blockOk ) {
404 4         199 goto return_error;
405             }
406 29705 100       78579 if ($isToken) {
407 11089         19036 $lexeme = $_;
408 11089         24339 last;
409             }
410             }
411             }
412             }
413             #
414             # Nothing ?
415             #
416 21582 50       57799 if ( Undef->check($lexeme) ) {
417 0         0 goto return_error;
418             }
419             #
420             # If it is a word, check if this is eventually a macro
421             #
422 21582 100       250233 if ( $lexeme eq 'WORD' ) {
423 3089         5935 my $thisMacro;
424             my $lparenPos;
425 3089 100       5694 if ($self->parser_isMacro(
426 3089         62054 ${$inputRef}, $rc{pos}, $maxPos,
427             $lexemeValue, $lexemeLength, \$thisMacro,
428             \$lparenPos
429             )
430             )
431             {
432 2441         96231 my $canTrace = $self->_canTrace($thisMacro);
433 2441         101588 my $macroCallId
434             = $self->impl_macroExecuteHeader( $thisMacro,
435             $canTrace );
436             #
437             # Collect macro arguments
438             #
439 2441         20769 my @args = ();
440              
441 2441 100       6668 if ( $lparenPos >= 0 ) {
442              
443 1854         34456 $self->_set__parse_level( $self->_parse_level + 1 );
444 1854         103108 my $dict = $self->_parseByGrammar(
445             $inputRef, $lparenPos,
446             $BYMACROARGUMENTS_G, $thisMacro
447             );
448 1853         178449 $self->_set__parse_level( $self->_parse_level - 1 );
449 1853 50       84373 if ( Undef->check($dict) ) {
450 0         0 goto return_error;
451             }
452 1853         24252 @args = $dict->{value}->value_elements;
453 1853         90266 $lexemeLength = $dict->{pos} - $rc{pos};
454             }
455             #
456             # It is the reponsability of implementation to make sure
457             # that a macro never croaks.
458             #
459             $lexemeValue
460 2440         46422 = $self->impl_macroExecuteNoHeader( $thisMacro,
461             $macroCallId, $canTrace, @args );
462             #
463             # Eventual postmatch length
464             #
465             $lexemeLength
466             += $thisMacro->macro_postMatchLengthExecute( $self,
467 2438         24251 ${$inputRef}, $rc{pos} + $lexemeLength, $maxPos );
  2438         50332  
468             #
469             # Input is changing
470             #
471 2438 100       9812 if ( M4Macro->check($lexemeValue) ) {
472             #
473             # Protect the case of M4Macro
474             #
475 15         571 $lexeme = 'ANYTHING';
476             }
477             else {
478             # $self->logger_debug(
479             # '[%d..%d/%d] Input is changing: replace %s by %s',
480             # $rc{pos},
481             # $rc{pos},
482             # $maxPos,
483             # substr(
484             # ${$inputRef}, $rc{pos}, $lexemeLength
485             # ),
486             # $lexemeValue
487             # );
488             substr(
489 2423         14875 ${$inputRef}, $rc{pos},
490 2423         36622 $lexemeLength, $lexemeValue
491             );
492              
493             # $self->logger_debug( '[%d..%d/%d] New input: %s',
494             # $rc{pos}, $rc{pos}, $maxPos, ${$inputRef} );
495              
496 2423         5930 $maxPos = length( ${$inputRef} ) - 1;
  2423         10690  
497 2423         124034 goto again;
498             }
499             }
500             else {
501             # $self->logger_debug(
502             # '[%d..%d/%d] %s is not an acceptable macro call',
503             # $rc{pos}, $rc{pos}, $maxPos, $lexemeValue );
504             }
505             }
506             #
507             # When _parse_level is zero, the current token has been fully
508             # parsed, and its output is to
509             # to be immediately "flushed".
510             # We do not need to do a lexeme_read(), nor a resume in this case:
511             # we know where we are.
512             #
513 19156 100       77601 if ( $self->_parse_level > 0 ) {
514 16277         59485 $r->lexeme_read( $lexeme, 0, 1, $lexemeValue );
515 16277         1534725 $prevPos = $rc{pos};
516 16277         80174 $rc{pos} += $lexemeLength;
517              
518             # $self->logger_debug( '[%d->%d/%d] %s: %s',
519             # $prevPos, $rc{pos}, $maxPos, $lexeme, $lexemeValue );
520              
521             #
522             # We can safely ignore the events from lexeme_read(),
523             # because we made sure in the grammar that resume() will
524             # NOT advance the position, thanks to those events:
525             #
526             # ^token
527             # ^ANYTHING
528             # macroArguments$
529             # token$
530             #
531             # macroArguments$, if it happens will always be standalone.
532             # token$, when it happen, can be mixed with ^token or
533             # ^ANYTHING.
534             #
535             # Please note that we do not use resume().
536             #
537             }
538             else {
539             #
540             # We are at the top level: flush to current diversion
541             #
542             # $self->logger_debug( '[%d->%d/%d] %s: %s',
543             # $prevPos, $rc{pos}, $maxPos, $lexeme, $lexemeValue );
544              
545 2879         53565 my $tmpValue = MarpaX::Languages::M4::Impl::Value->new()
546             ->value_push($lexemeValue);
547 2879         176556 $self->impl_appendValue(
548             $tmpValue->value_concat->value_firstElement );
549 2879         7460 $prevPos = $rc{pos};
550 2879         16668 $rc{pos} += $lexemeLength;
551             }
552             }
553              
554 2010 100       9841 if ( $self->_parse_level > 0 ) {
555             #
556             # We are in the context of a recursive call: the output
557             # is of concern for a macro that called us.
558             #
559 1856         4814 local $MarpaX::Languages::M4::Impl::Parser::macro = $macro;
560             #
561             # For $r->value() optimisations
562             #
563 1856         3845 state $registrations = undef;
564              
565 1856 100       6714 if (defined($registrations)) {
566 1855         10519 $r->registrations($registrations);
567             }
568 1856         10904 my $valueRef = $r->value;
569 1856 100       204509 if (! defined($registrations)) {
570 1         6 $registrations = $r->registrations();
571             }
572 1856 100 66     7436 if ( Undef->check($valueRef) || Undef->check( ${$valueRef} ) ) {
  1855         25831  
573 1         19 goto return_error;
574             }
575              
576 1855         14281 $rc{value} = ${$valueRef};
  1855         7348  
577             }
578             else {
579             #
580             # We are at the top level: the output has already been
581             # "flushed" to whatever the current diversion said to.
582             #
583             }
584              
585             # $self->logger_debug( '[%d..%d/%d] => %s',
586             # $rc{pos}, $rc{pos}, $maxPos, \%rc );
587              
588 2009         105393 return \%rc;
589              
590             return_error:
591             #
592             # We propagate the undef to all levels except number 0
593             #
594 5 100       42 if ( $self->_parse_level > 0 ) {
595 1 50 33     36 if ( $self->_parse_level == 1 && $self->impl_eoi ) {
596             #
597             # We want the parsing to stop now
598             #
599 1         26 $self->impl_raiseException('EOF during argument collection');
600             }
601 0         0 return;
602             }
603             else {
604 4         210 return \%rc;
605             }
606             }
607              
608             #
609             # M4 says that a token is processed as soon as it is recognized.
610             # So we loop on token recognition
611             #
612 1 50 33 1   2966 method _parseByTokens (Ref['SCALAR'] $inputRef --> Str) {
  1 50   1   2  
  1 50   164   126  
  1 50       6  
  1 50       2  
  1         176  
  1         13212  
  164         2242  
  164         610  
  164         721  
  164         589  
  164         459  
  164         1829  
  164         446  
613              
614 164         3631 my $rc = $self->_parseByGrammar( $inputRef, 0, $BYTOKEN_G );
615 161 100       12001 if ( !Undef->check($rc) ) {
616 160         1926 return substr( ${$inputRef}, $rc->{pos} );
  160         3731  
617             }
618              
619 1         15 return ${$inputRef};
  1         16  
620             }
621              
622             }
623              
624             1;
625              
626             __END__
627              
628             =pod
629              
630             =encoding UTF-8
631              
632             =head1 NAME
633              
634             MarpaX::Languages::M4::Impl::Parser - M4 Marpa parser
635              
636             =head1 VERSION
637              
638             version 0.020
639              
640             =head1 AUTHOR
641              
642             Jean-Damien Durand <jeandamiendurand@free.fr>
643              
644             =head1 COPYRIGHT AND LICENSE
645              
646             This software is copyright (c) 2015 by Jean-Damien Durand.
647              
648             This is free software; you can redistribute it and/or modify it under
649             the same terms as the Perl 5 programming language system itself.
650              
651             =cut