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         4  
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   89871 class MarpaX::Languages::M4::Impl::Parser {
  1     1   27  
  1         6  
  1         2  
  1         55  
  1         297  
  1         1505  
  1         3  
  1         1220  
  1         3  
  1         5  
  1         58  
  1         9  
  1         42  
  1         5  
  1         1  
  1         89  
  1         46  
  1         9  
  1         2  
  1         14  
  1         3889  
  1         3  
  1         6  
  1         579  
  1         3073  
  1         3  
  1         134  
  1         3  
  1         7  
  1         322  
  1         6373  
  1         8  
  1         549  
  1         2157  
  1         6  
  1         1058  
  1         2087  
  1         6  
  1         103021  
  1         4  
  1         5  
  1         2  
  1         20  
  1         4  
  1         2  
  1         38  
  1         6  
  1         1  
  1         88  
  1         6232  
  0         0  
12 1     1   311 use MarpaX::Languages::M4::Impl::Parser::Actions;
  1         3  
  1         10  
13 1     1   49 use MarpaX::Languages::M4::Type::Macro -all;
  1         45  
  1         6  
14 1     1   812 use MarpaX::Languages::M4::Impl::Value;
  1         4  
  1         7  
15 1     1   441 use Marpa::R2; # 2.103_004;
  1         104830  
  1         14  
16 1     1   44 use Scalar::Util qw/readonly/;
  1         2  
  1         58  
17 1     1   5 use Types::Common::Numeric -all;
  1         2  
  1         8  
18             #
19             # --nesting_limit (SHOULD) take care of that
20             #
21 1     1   5460 no warnings 'recursion';
  1         3  
  1         217  
22              
23 1         17 our $VERSION = '0.018'; # VERSION
24              
25 1         4 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         32  
102             }
103             );
104             };
105 1         194252 our $BYMACROARGUMENTS_G = do {
106             my $g = Marpa::R2::Scanless::G->new(
107 1         3 { source => \do {":start ::= macroArguments\n$BASE_GRAMMAR"}
  1         25  
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   6 no warnings 'redefine';
  1     0   2  
  1         405  
119              
120             sub Marpa::R2::Recognizer::registrations {
121 2024     2024 0 3460 my $recce = shift;
122 2024 100       4853 if (@_) {
123 2022         3202 my $hash = shift;
124 2022 50 33     13062 if (! defined($hash) ||
      33        
125             ref($hash) ne 'HASH' ||
126 14154         33500 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         4179 $recce->[Marpa::R2::Internal::Recognizer::NULL_VALUES] = $hash->{NULL_VALUES};
143 2022         4052 $recce->[Marpa::R2::Internal::Recognizer::REGISTRATIONS] = $hash->{REGISTRATIONS};
144 2022         3616 $recce->[Marpa::R2::Internal::Recognizer::CLOSURE_BY_SYMBOL_ID] = $hash->{CLOSURE_BY_SYMBOL_ID};
145 2022         3447 $recce->[Marpa::R2::Internal::Recognizer::CLOSURE_BY_RULE_ID] = $hash->{CLOSURE_BY_RULE_ID};
146 2022         3475 $recce->[Marpa::R2::Internal::Recognizer::RESOLVE_PACKAGE] = $hash->{RESOLVE_PACKAGE};
147 2022         3653 $recce->[Marpa::R2::Internal::Recognizer::RESOLVE_PACKAGE_SOURCE] = $hash->{RESOLVE_PACKAGE_SOURCE};
148 2022         3566 $recce->[Marpa::R2::Internal::Recognizer::PER_PARSE_CONSTRUCTOR] = $hash->{PER_PARSE_CONSTRUCTOR};
149             }
150             return {
151 2024         14835 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   3831 my $slr = shift;
163 2024         3446 my $thick_g1_recce =
164             $slr->[Marpa::R2::Internal::Scanless::R::THICK_G1_RECCE];
165 2024         6241 return $thick_g1_recce->registrations(@_);
166             } ## end sub Marpa::R2::Scanless::R::registrations
167              
168             }
169              
170 1         67105 has _parse_level => (
171             is => 'rwp',
172             isa => PositiveOrZeroInt,
173              
174             # trigger => 1,
175             default => 0
176             );
177              
178 1 0   1   2848 method _trigger__parse_level (PositiveOrZeroInt $parse_level, @rest) {
  1 0   1   2  
  1 0   0   127  
  1 0       6  
  1 0       2  
  1 0       138  
  1         1955  
  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   2157 method parser_parse (Str $input --> Str) {
  1 50   1   3  
  1 50   164   122  
  1 50       5  
  1 50       2  
  1         84  
  1         234  
  164         1907  
  164         645  
  164         668  
  164         500  
  164         380  
  164         631  
  164         282  
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         382 my $work = $input;
199 164         2853 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   17124 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   135  
  1 50   1   5  
  1 50   1   2  
  1 50   2018   123  
  1 50       6  
  1 50       1  
  1 50       91  
  1 50       5  
  1 50       2  
  1 50       107  
  1 100       5  
  1 50       1  
  1 100       2091  
  1         2273  
  2018         17666  
  2018         6254  
  2018         4912  
  2018         6145  
  2018         5157  
  2018         3021  
  2018         12214  
  2018         5455  
  2018         4768  
  2018         2799  
  2018         6417  
  2018         4893  
  2018         4261  
  2018         2848  
  2018         7803  
  2018         5563  
  2018         5296  
  1854         2722  
  1854         5074  
  2018         35596  
207              
208 2018         3216 my $maxPos = length( ${$inputRef} ) - 1;
  2018         5151  
209             #
210             # Protect the case of empty string.
211             # This is affecting all parsing levels.
212             #
213 2018 100       4530 if ( $pos > $maxPos ) {
214 1         18 return;
215             }
216             #
217             # Get the lexemes ordering
218             #
219 2017         7499 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       98646 if ( $g == $BYMACROARGUMENTS_G ) {
226 1854         7069 unshift( @lexemeNames, 'NOPARAM', 'LPAREN', 'RPAREN', 'COMMA' );
227             }
228              
229 2017         32476 my $value = MarpaX::Languages::M4::Impl::Value->new();
230 2017         59768 my %rc = ( pos => $pos, value => $value );
231              
232             #
233             # Instanciate and start recognizer
234             #
235 2017         15093 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         593046 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         8277 $r->read( \'(' );
258              
259             again:
260 4440         203928 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         34713 my %expected = map { $_ => 1 } @{ $r->terminals_expected };
  186963         2554807  
  23409         65883  
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       99069 if ( $r->exhausted ) {
275              
276             # $self->logger_debug( '[%d..%d/%d] Parse is exhausted',
277             # $rc{pos}, $rc{pos}, $maxPos );
278              
279 1823         19286 last;
280             }
281              
282 21586         273627 my $lexemeValue;
283             my $lexemeLength;
284 21586         0 my $lexeme;
285              
286 21586         0 my $QuotedstringValue;
287 21586         0 my $QuotedstringLength;
288 21586         55017 my $isQuotedString = false;
289              
290 21586         69566 my $CommentValue;
291             my $CommentLength;
292 21586         43762 my $isComment = false;
293              
294 21586         70240 my $canCollectArguments = true;
295 21586 100       80174 if ( $g == $BYMACROARGUMENTS_G ) {
296 16948         33977 my $blockOk = false;
297             try {
298             $isQuotedString
299 16948         354367 = $self->parser_isQuotedstring( ${$inputRef},
300             $rc{pos},
301 16948     16948   391720 $maxPos, \$QuotedstringValue, \$QuotedstringLength );
302             $isComment
303 16948         251727 = $self->parser_isComment( ${$inputRef}, $rc{pos},
304 16948         361943 $maxPos, \$CommentValue, \$CommentLength );
305 16948   100     382419 $canCollectArguments = !$isQuotedString && !$isComment;
306 16948         37119 $blockOk = true;
307 16948         123657 };
308 16948 50       242980 if ( !$blockOk ) {
309 0         0 goto return_error;
310             }
311             }
312              
313 21586         47045 foreach (@lexemeNames) {
314 112029 100       287207 if ( $_ eq 'NOPARAM' ) {
    100          
    100          
    100          
315 16948 100 66     49632 if ( exists( $expected{NOPARAM} )
316             && $canCollectArguments )
317             {
318 1854         3632 pos( ${$inputRef} ) = $rc{pos};
  1854         5848  
319 1854 100       3991 if ( ${$inputRef} =~ /\G\(\s*\)/s ) {
  1854         10282  
320 15         35 $lexeme = 'NOPARAM';
321 15         29 $lexemeValue = substr( ${$inputRef}, $-[0],
  15         114  
322             $+[0] - $-[0] );
323 15         69 $lexemeLength = $+[0] - $-[0];
324 15         38 last;
325             }
326             }
327             }
328             elsif ( $_ eq 'LPAREN' ) {
329 16933 100 66     50584 if ( exists( $expected{LPAREN} )
      66        
      66        
330             && $canCollectArguments
331 12860         20570 && do { pos( ${$inputRef} ) = $rc{pos}; 1 }
  12860         33196  
  12860         36409  
332 12860         55501 && ${$inputRef} =~ /\G\(\s*/
333             )
334             {
335 1870         3120 $lexeme = 'LPAREN';
336 1870         12475 $lexemeLength = $+[0] - $-[0];
337             $lexemeValue
338 1870         3469 = substr( ${$inputRef}, $-[0], $lexemeLength );
  1870         7930  
339 1870         3655 last;
340             }
341             }
342             elsif ( $_ eq 'RPAREN' ) {
343 15063 100 66     45460 if ( exists( $expected{RPAREN} )
      100        
344             && $canCollectArguments
345 10990         35626 && substr( ${$inputRef}, $rc{pos}, 1 ) eq ')' )
346             {
347 1869         3355 $lexeme = 'RPAREN';
348 1869         2887 $lexemeValue = ')';
349 1869         2830 $lexemeLength = 1;
350 1869         3188 last;
351             }
352             }
353             elsif ( $_ eq 'COMMA' ) {
354 13194 100 100     37783 if ( exists( $expected{COMMA} ) && $canCollectArguments )
355             {
356 9025         12742 pos( ${$inputRef} ) = $rc{pos};
  9025         17202  
357 9025 100       14742 if ( ${$inputRef} =~ /\G,\s*/s ) {
  9025         26140  
358 2666         4447 $lexeme = 'COMMA';
359 2666         3545 $lexemeValue = substr( ${$inputRef}, $-[0],
  2666         25310  
360             $+[0] - $-[0] );
361 2666         16670 $lexemeLength = $+[0] - $-[0];
362 2666         5179 last;
363             }
364             }
365             }
366             else {
367 49891 100 100     198352 if ( $g == $BYMACROARGUMENTS_G && $_ eq 'QUOTEDSTRING' ) {
    100 100        
368             #
369             # Already done in the context of macro arguments grammar
370             #
371 9654 100       20712 if ($isQuotedString) {
372 4068         6034 $lexeme = $_;
373 4068         6468 $lexemeValue = $QuotedstringValue;
374 4068         5473 $lexemeLength = $QuotedstringLength;
375 4068         6942 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       23564 if ($isComment) {
383 5         11 $lexeme = $_;
384 5         9 $lexemeValue = $CommentValue;
385 5         10 $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         80922 my $method = 'parser_is' . ucfirst( lc($_) );
396 29709         58553 my $blockOk = false;
397 29709         89726 my $isToken;
398             try {
399 29709         598436 $isToken = $self->$method( ${$inputRef}, $rc{pos},
400 29709     29709   650499 $maxPos, \$lexemeValue, \$lexemeLength );
401 29705         688320 $blockOk = true;
402 29709         155005 };
403 29709 100       403023 if ( !$blockOk ) {
404 4         124 goto return_error;
405             }
406 29705 100       78703 if ($isToken) {
407 11089         17552 $lexeme = $_;
408 11089         21406 last;
409             }
410             }
411             }
412             }
413             #
414             # Nothing ?
415             #
416 21582 50       53832 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       222718 if ( $lexeme eq 'WORD' ) {
423 3089         5026 my $thisMacro;
424             my $lparenPos;
425 3089 100       4268 if ($self->parser_isMacro(
426 3089         54482 ${$inputRef}, $rc{pos}, $maxPos,
427             $lexemeValue, $lexemeLength, \$thisMacro,
428             \$lparenPos
429             )
430             )
431             {
432 2441         90586 my $canTrace = $self->_canTrace($thisMacro);
433 2441         89566 my $macroCallId
434             = $self->impl_macroExecuteHeader( $thisMacro,
435             $canTrace );
436             #
437             # Collect macro arguments
438             #
439 2441         19612 my @args = ();
440              
441 2441 100       5685 if ( $lparenPos >= 0 ) {
442              
443 1854         29447 $self->_set__parse_level( $self->_parse_level + 1 );
444 1854         89412 my $dict = $self->_parseByGrammar(
445             $inputRef, $lparenPos,
446             $BYMACROARGUMENTS_G, $thisMacro
447             );
448 1853         144283 $self->_set__parse_level( $self->_parse_level - 1 );
449 1853 50       69747 if ( Undef->check($dict) ) {
450 0         0 goto return_error;
451             }
452 1853         19559 @args = $dict->{value}->value_elements;
453 1853         82100 $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         39873 = $self->impl_macroExecuteNoHeader( $thisMacro,
461             $macroCallId, $canTrace, @args );
462             #
463             # Eventual postmatch length
464             #
465             $lexemeLength
466             += $thisMacro->macro_postMatchLengthExecute( $self,
467 2438         19920 ${$inputRef}, $rc{pos} + $lexemeLength, $maxPos );
  2438         38698  
468             #
469             # Input is changing
470             #
471 2438 100       9169 if ( M4Macro->check($lexemeValue) ) {
472             #
473             # Protect the case of M4Macro
474             #
475 15         436 $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         11687 ${$inputRef}, $rc{pos},
490 2423         30099 $lexemeLength, $lexemeValue
491             );
492              
493             # $self->logger_debug( '[%d..%d/%d] New input: %s',
494             # $rc{pos}, $rc{pos}, $maxPos, ${$inputRef} );
495              
496 2423         4389 $maxPos = length( ${$inputRef} ) - 1;
  2423         8099  
497 2423         86677 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       75737 if ( $self->_parse_level > 0 ) {
514 16277         59250 $r->lexeme_read( $lexeme, 0, 1, $lexemeValue );
515 16277         1388701 $prevPos = $rc{pos};
516 16277         71109 $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         49662 my $tmpValue = MarpaX::Languages::M4::Impl::Value->new()
546             ->value_push($lexemeValue);
547 2879         166658 $self->impl_appendValue(
548             $tmpValue->value_concat->value_firstElement );
549 2879         7058 $prevPos = $rc{pos};
550 2879         16403 $rc{pos} += $lexemeLength;
551             }
552             }
553              
554 2010 100       6618 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         4027 local $MarpaX::Languages::M4::Impl::Parser::macro = $macro;
560             #
561             # For $r->value() optimisations
562             #
563 1856         3100 state $registrations = undef;
564              
565 1856 100       3920 if (defined($registrations)) {
566 1855         6420 $r->registrations($registrations);
567             }
568 1856         7701 my $valueRef = $r->value;
569 1856 100       177424 if (! defined($registrations)) {
570 1         9 $registrations = $r->registrations();
571             }
572 1856 100 66     4931 if ( Undef->check($valueRef) || Undef->check( ${$valueRef} ) ) {
  1855         22763  
573 1         16 goto return_error;
574             }
575              
576 1855         12735 $rc{value} = ${$valueRef};
  1855         4426  
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         77502 return \%rc;
589              
590             return_error:
591             #
592             # We propagate the undef to all levels except number 0
593             #
594 5 100       24 if ( $self->_parse_level > 0 ) {
595 1 50 33     33 if ( $self->_parse_level == 1 && $self->impl_eoi ) {
596             #
597             # We want the parsing to stop now
598             #
599 1         24 $self->impl_raiseException('EOF during argument collection');
600             }
601 0         0 return;
602             }
603             else {
604 4         138 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   2665 method _parseByTokens (Ref['SCALAR'] $inputRef --> Str) {
  1 50   1   2  
  1 50   164   120  
  1 50       5  
  1 50       2  
  1         169  
  1         16478  
  164         1788  
  164         521  
  164         590  
  164         565  
  164         315  
  164         1263  
  164         405  
613              
614 164         2965 my $rc = $self->_parseByGrammar( $inputRef, 0, $BYTOKEN_G );
615 161 100       10380 if ( !Undef->check($rc) ) {
616 160         1640 return substr( ${$inputRef}, $rc->{pos} );
  160         3396  
617             }
618              
619 1         18 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.018
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