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   5 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   92111 class MarpaX::Languages::M4::Impl::Parser {
  1     1   27  
  1         9  
  1         2  
  1         56  
  1         281  
  1         1494  
  1         3  
  1         1254  
  1         2  
  1         8  
  1         62  
  1         9  
  1         45  
  1         6  
  1         2  
  1         91  
  1         29  
  1         5  
  1         2  
  1         9  
  1         4199  
  1         2  
  1         7  
  1         703  
  1         3479  
  1         4  
  1         135  
  1         3  
  1         8  
  1         324  
  1         6018  
  1         11  
  1         550  
  1         2313  
  1         6  
  1         1102  
  1         2294  
  1         7  
  1         110630  
  1         4  
  1         5  
  1         1  
  1         22  
  1         5  
  1         2  
  1         41  
  1         6  
  1         1  
  1         107  
  1         6835  
  0         0  
12 1     1   365 use MarpaX::Languages::M4::Impl::Parser::Actions;
  1         3  
  1         12  
13 1     1   56 use MarpaX::Languages::M4::Type::Macro -all;
  1         51  
  1         7  
14 1     1   878 use MarpaX::Languages::M4::Impl::Value;
  1         2  
  1         4  
15 1     1   423 use Marpa::R2; # 2.103_004;
  1         123594  
  1         21  
16 1     1   52 use Scalar::Util qw/readonly/;
  1         2  
  1         86  
17 1     1   7 use Types::Common::Numeric -all;
  1         2  
  1         10  
18             #
19             # --nesting_limit (SHOULD) take care of that
20             #
21 1     1   5732 no warnings 'recursion';
  1         2  
  1         263  
22              
23 1         13 our $VERSION = '0.019'; # VERSION
24              
25 1         3 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         1 our $BYTOKEN_G = do {
100             my $g = Marpa::R2::Scanless::G->new(
101 1         2 { source => \do {":start ::= tokens\n$BASE_GRAMMAR"}
  1         47  
102             }
103             );
104             };
105 1         204949 our $BYMACROARGUMENTS_G = do {
106             my $g = Marpa::R2::Scanless::G->new(
107 1         4 { source => \do {":start ::= macroArguments\n$BASE_GRAMMAR"}
  1         30  
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         439  
119              
120             sub Marpa::R2::Recognizer::registrations {
121 2024     2024 0 3882 my $recce = shift;
122 2024 100       5312 if (@_) {
123 2022         4795 my $hash = shift;
124 2022 50 33     16005 if (! defined($hash) ||
      33        
125             ref($hash) ne 'HASH' ||
126 14154         36579 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         5391 $recce->[Marpa::R2::Internal::Recognizer::NULL_VALUES] = $hash->{NULL_VALUES};
143 2022         4660 $recce->[Marpa::R2::Internal::Recognizer::REGISTRATIONS] = $hash->{REGISTRATIONS};
144 2022         3927 $recce->[Marpa::R2::Internal::Recognizer::CLOSURE_BY_SYMBOL_ID] = $hash->{CLOSURE_BY_SYMBOL_ID};
145 2022         3978 $recce->[Marpa::R2::Internal::Recognizer::CLOSURE_BY_RULE_ID] = $hash->{CLOSURE_BY_RULE_ID};
146 2022         5087 $recce->[Marpa::R2::Internal::Recognizer::RESOLVE_PACKAGE] = $hash->{RESOLVE_PACKAGE};
147 2022         4068 $recce->[Marpa::R2::Internal::Recognizer::RESOLVE_PACKAGE_SOURCE] = $hash->{RESOLVE_PACKAGE_SOURCE};
148 2022         4440 $recce->[Marpa::R2::Internal::Recognizer::PER_PARSE_CONSTRUCTOR] = $hash->{PER_PARSE_CONSTRUCTOR};
149             }
150             return {
151 2024         19423 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   5197 my $slr = shift;
163 2024         4393 my $thick_g1_recce =
164             $slr->[Marpa::R2::Internal::Scanless::R::THICK_G1_RECCE];
165 2024         7477 return $thick_g1_recce->registrations(@_);
166             } ## end sub Marpa::R2::Scanless::R::registrations
167              
168             }
169              
170 1         74624 has _parse_level => (
171             is => 'rwp',
172             isa => PositiveOrZeroInt,
173              
174             # trigger => 1,
175             default => 0
176             );
177              
178 1 0   1   2992 method _trigger__parse_level (PositiveOrZeroInt $parse_level, @rest) {
  1 0   1   2  
  1 0   0   127  
  1 0       5  
  1 0       3  
  1 0       145  
  1         2667  
  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   2285 method parser_parse (Str $input --> Str) {
  1 50   1   3  
  1 50   164   129  
  1 50       6  
  1 50       2  
  1         85  
  1         409  
  164         2060  
  164         676  
  164         737  
  164         574  
  164         423  
  164         705  
  164         313  
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         359 my $work = $input;
199 164         3163 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   19676 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   2  
  1 50   1   165  
  1 50   1   6  
  1 50   1   2  
  1 50   2018   122  
  1 50       9  
  1 50       3  
  1 50       93  
  1 50       6  
  1 50       1  
  1 50       110  
  1 100       5  
  1 50       2  
  1 100       2151  
  1         2816  
  2018         20158  
  2018         6076  
  2018         6347  
  2018         6683  
  2018         5863  
  2018         4393  
  2018         14714  
  2018         5964  
  2018         5523  
  2018         2980  
  2018         7119  
  2018         6250  
  2018         6050  
  2018         4090  
  2018         10477  
  2018         6694  
  2018         5519  
  1854         2987  
  1854         5967  
  2018         39453  
207              
208 2018         3755 my $maxPos = length( ${$inputRef} ) - 1;
  2018         5533  
209             #
210             # Protect the case of empty string.
211             # This is affecting all parsing levels.
212             #
213 2018 100       5544 if ( $pos > $maxPos ) {
214 1         18 return;
215             }
216             #
217             # Get the lexemes ordering
218             #
219 2017         8925 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       111328 if ( $g == $BYMACROARGUMENTS_G ) {
226 1854         8024 unshift( @lexemeNames, 'NOPARAM', 'LPAREN', 'RPAREN', 'COMMA' );
227             }
228              
229 2017         36932 my $value = MarpaX::Languages::M4::Impl::Value->new();
230 2017         68612 my %rc = ( pos => $pos, value => $value );
231              
232             #
233             # Instanciate and start recognizer
234             #
235 2017         18000 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         681443 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         9195 $r->read( \'(' );
258              
259             again:
260 4440         233644 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         41132 my %expected = map { $_ => 1 } @{ $r->terminals_expected };
  186963         2714551  
  23409         65928  
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       106006 if ( $r->exhausted ) {
275              
276             # $self->logger_debug( '[%d..%d/%d] Parse is exhausted',
277             # $rc{pos}, $rc{pos}, $maxPos );
278              
279 1823         20017 last;
280             }
281              
282 21586         285953 my $lexemeValue;
283             my $lexemeLength;
284 21586         0 my $lexeme;
285              
286 21586         0 my $QuotedstringValue;
287 21586         0 my $QuotedstringLength;
288 21586         68384 my $isQuotedString = false;
289              
290 21586         78419 my $CommentValue;
291             my $CommentLength;
292 21586         40783 my $isComment = false;
293              
294 21586         74830 my $canCollectArguments = true;
295 21586 100       91899 if ( $g == $BYMACROARGUMENTS_G ) {
296 16948         30800 my $blockOk = false;
297             try {
298             $isQuotedString
299 16948         375149 = $self->parser_isQuotedstring( ${$inputRef},
300             $rc{pos},
301 16948     16948   418330 $maxPos, \$QuotedstringValue, \$QuotedstringLength );
302             $isComment
303 16948         272955 = $self->parser_isComment( ${$inputRef}, $rc{pos},
304 16948         397989 $maxPos, \$CommentValue, \$CommentLength );
305 16948   100     426204 $canCollectArguments = !$isQuotedString && !$isComment;
306 16948         41256 $blockOk = true;
307 16948         139422 };
308 16948 50       263075 if ( !$blockOk ) {
309 0         0 goto return_error;
310             }
311             }
312              
313 21586         49164 foreach (@lexemeNames) {
314 112029 100       290110 if ( $_ eq 'NOPARAM' ) {
    100          
    100          
    100          
315 16948 100 66     46684 if ( exists( $expected{NOPARAM} )
316             && $canCollectArguments )
317             {
318 1854         4193 pos( ${$inputRef} ) = $rc{pos};
  1854         6380  
319 1854 100       3758 if ( ${$inputRef} =~ /\G\(\s*\)/s ) {
  1854         11386  
320 15         40 $lexeme = 'NOPARAM';
321 15         30 $lexemeValue = substr( ${$inputRef}, $-[0],
  15         121  
322             $+[0] - $-[0] );
323 15         77 $lexemeLength = $+[0] - $-[0];
324 15         50 last;
325             }
326             }
327             }
328             elsif ( $_ eq 'LPAREN' ) {
329 16933 100 66     60674 if ( exists( $expected{LPAREN} )
      66        
      66        
330             && $canCollectArguments
331 12860         22610 && do { pos( ${$inputRef} ) = $rc{pos}; 1 }
  12860         41295  
  12860         40825  
332 12860         53345 && ${$inputRef} =~ /\G\(\s*/
333             )
334             {
335 1870         4288 $lexeme = 'LPAREN';
336 1870         14509 $lexemeLength = $+[0] - $-[0];
337             $lexemeValue
338 1870         4717 = substr( ${$inputRef}, $-[0], $lexemeLength );
  1870         9092  
339 1870         4091 last;
340             }
341             }
342             elsif ( $_ eq 'RPAREN' ) {
343 15063 100 66     49590 if ( exists( $expected{RPAREN} )
      100        
344             && $canCollectArguments
345 10990         41741 && substr( ${$inputRef}, $rc{pos}, 1 ) eq ')' )
346             {
347 1869         3879 $lexeme = 'RPAREN';
348 1869         3585 $lexemeValue = ')';
349 1869         3187 $lexemeLength = 1;
350 1869         3304 last;
351             }
352             }
353             elsif ( $_ eq 'COMMA' ) {
354 13194 100 100     41309 if ( exists( $expected{COMMA} ) && $canCollectArguments )
355             {
356 9025         14526 pos( ${$inputRef} ) = $rc{pos};
  9025         20097  
357 9025 100       15573 if ( ${$inputRef} =~ /\G,\s*/s ) {
  9025         30947  
358 2666         4966 $lexeme = 'COMMA';
359 2666         4014 $lexemeValue = substr( ${$inputRef}, $-[0],
  2666         26427  
360             $+[0] - $-[0] );
361 2666         17067 $lexemeLength = $+[0] - $-[0];
362 2666         5641 last;
363             }
364             }
365             }
366             else {
367 49891 100 100     207650 if ( $g == $BYMACROARGUMENTS_G && $_ eq 'QUOTEDSTRING' ) {
    100 100        
368             #
369             # Already done in the context of macro arguments grammar
370             #
371 9654 100       20881 if ($isQuotedString) {
372 4068         6070 $lexeme = $_;
373 4068         7206 $lexemeValue = $QuotedstringValue;
374 4068         5763 $lexemeLength = $QuotedstringLength;
375 4068         7794 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       25514 if ($isComment) {
383 5         11 $lexeme = $_;
384 5         9 $lexemeValue = $CommentValue;
385 5         9 $lexemeLength = $CommentLength;
386 5         10 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         83813 my $method = 'parser_is' . ucfirst( lc($_) );
396 29709         73021 my $blockOk = false;
397 29709         100416 my $isToken;
398             try {
399 29709         634105 $isToken = $self->$method( ${$inputRef}, $rc{pos},
400 29709     29709   691309 $maxPos, \$lexemeValue, \$lexemeLength );
401 29705         761513 $blockOk = true;
402 29709         168918 };
403 29709 100       444848 if ( !$blockOk ) {
404 4         241 goto return_error;
405             }
406 29705 100       84409 if ($isToken) {
407 11089         18857 $lexeme = $_;
408 11089         21959 last;
409             }
410             }
411             }
412             }
413             #
414             # Nothing ?
415             #
416 21582 50       62630 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       241719 if ( $lexeme eq 'WORD' ) {
423 3089         6368 my $thisMacro;
424             my $lparenPos;
425 3089 100       7948 if ($self->parser_isMacro(
426 3089         59519 ${$inputRef}, $rc{pos}, $maxPos,
427             $lexemeValue, $lexemeLength, \$thisMacro,
428             \$lparenPos
429             )
430             )
431             {
432 2441         97055 my $canTrace = $self->_canTrace($thisMacro);
433 2441         98825 my $macroCallId
434             = $self->impl_macroExecuteHeader( $thisMacro,
435             $canTrace );
436             #
437             # Collect macro arguments
438             #
439 2441         20569 my @args = ();
440              
441 2441 100       6919 if ( $lparenPos >= 0 ) {
442              
443 1854         32208 $self->_set__parse_level( $self->_parse_level + 1 );
444 1854         99875 my $dict = $self->_parseByGrammar(
445             $inputRef, $lparenPos,
446             $BYMACROARGUMENTS_G, $thisMacro
447             );
448 1853         162109 $self->_set__parse_level( $self->_parse_level - 1 );
449 1853 50       81173 if ( Undef->check($dict) ) {
450 0         0 goto return_error;
451             }
452 1853         21981 @args = $dict->{value}->value_elements;
453 1853         91648 $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         44226 = $self->impl_macroExecuteNoHeader( $thisMacro,
461             $macroCallId, $canTrace, @args );
462             #
463             # Eventual postmatch length
464             #
465             $lexemeLength
466             += $thisMacro->macro_postMatchLengthExecute( $self,
467 2438         22072 ${$inputRef}, $rc{pos} + $lexemeLength, $maxPos );
  2438         45627  
468             #
469             # Input is changing
470             #
471 2438 100       10333 if ( M4Macro->check($lexemeValue) ) {
472             #
473             # Protect the case of M4Macro
474             #
475 15         493 $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         13340 ${$inputRef}, $rc{pos},
490 2423         34618 $lexemeLength, $lexemeValue
491             );
492              
493             # $self->logger_debug( '[%d..%d/%d] New input: %s',
494             # $rc{pos}, $rc{pos}, $maxPos, ${$inputRef} );
495              
496 2423         4550 $maxPos = length( ${$inputRef} ) - 1;
  2423         9979  
497 2423         103272 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       78460 if ( $self->_parse_level > 0 ) {
514 16277         60715 $r->lexeme_read( $lexeme, 0, 1, $lexemeValue );
515 16277         1532901 $prevPos = $rc{pos};
516 16277         80668 $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         52509 my $tmpValue = MarpaX::Languages::M4::Impl::Value->new()
546             ->value_push($lexemeValue);
547 2879         177976 $self->impl_appendValue(
548             $tmpValue->value_concat->value_firstElement );
549 2879         7114 $prevPos = $rc{pos};
550 2879         17586 $rc{pos} += $lexemeLength;
551             }
552             }
553              
554 2010 100       8785 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         4245 local $MarpaX::Languages::M4::Impl::Parser::macro = $macro;
560             #
561             # For $r->value() optimisations
562             #
563 1856         3327 state $registrations = undef;
564              
565 1856 100       4894 if (defined($registrations)) {
566 1855         7956 $r->registrations($registrations);
567             }
568 1856         10109 my $valueRef = $r->value;
569 1856 100       196603 if (! defined($registrations)) {
570 1         5 $registrations = $r->registrations();
571             }
572 1856 100 66     6324 if ( Undef->check($valueRef) || Undef->check( ${$valueRef} ) ) {
  1855         25278  
573 1         19 goto return_error;
574             }
575              
576 1855         15419 $rc{value} = ${$valueRef};
  1855         5968  
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         89169 return \%rc;
589              
590             return_error:
591             #
592             # We propagate the undef to all levels except number 0
593             #
594 5 100       36 if ( $self->_parse_level > 0 ) {
595 1 50 33     34 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         183 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   3364 method _parseByTokens (Ref['SCALAR'] $inputRef --> Str) {
  1 50   1   4  
  1 50   164   154  
  1 50       6  
  1 50       3  
  1         203  
  1         14421  
  164         1920  
  164         588  
  164         918  
  164         775  
  164         285  
  164         1530  
  164         357  
613              
614 164         3237 my $rc = $self->_parseByGrammar( $inputRef, 0, $BYTOKEN_G );
615 161 100       12221 if ( !Undef->check($rc) ) {
616 160         1926 return substr( ${$inputRef}, $rc->{pos} );
  160         4026  
617             }
618              
619 1         13 return ${$inputRef};
  1         17  
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.019
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