Filename | /var/www/foswiki11/lib/Foswiki/Infix/Parser.pm |
Statements | Executed 5657 statements in 30.5ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
83 | 1 | 1 | 13.4ms | 19.8ms | __ANON__[:277] | Foswiki::Infix::Parser::
83 | 1 | 1 | 4.87ms | 31.6ms | _parse | Foswiki::Infix::Parser::
189 | 2 | 1 | 1.91ms | 2.48ms | _apply | Foswiki::Infix::Parser::
83 | 1 | 1 | 947µs | 947µs | _initialise | Foswiki::Infix::Parser::
83 | 3 | 3 | 889µs | 33.5ms | parse | Foswiki::Infix::Parser::
1 | 1 | 1 | 807µs | 878µs | BEGIN@21 | Foswiki::Infix::Parser::
518 | 7 | 1 | 686µs | 686µs | MONITOR_PARSER | Foswiki::Infix::Parser::
1 | 1 | 1 | 424µs | 522µs | BEGIN@20 | Foswiki::Infix::Parser::
65 | 2 | 2 | 208µs | 208µs | addOperator | Foswiki::Infix::Parser::
3 | 1 | 1 | 61µs | 61µs | new | Foswiki::Infix::Parser::
1 | 1 | 1 | 29µs | 327µs | BEGIN@19 | Foswiki::Infix::Parser::
1 | 1 | 1 | 26µs | 48µs | BEGIN@16 | Foswiki::Infix::Parser::
1 | 1 | 1 | 16µs | 25µs | BEGIN@17 | Foswiki::Infix::Parser::
1 | 1 | 1 | 16µs | 39µs | BEGIN@18 | Foswiki::Infix::Parser::
1 | 1 | 1 | 2µs | 2µs | finish | Foswiki::Infix::Parser::
0 | 0 | 0 | 0s | 0s | __ANON__[:282] | Foswiki::Infix::Parser::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # See bottom of file for license and copyright information | ||||
2 | |||||
3 | =begin TML | ||||
4 | |||||
5 | ---+ package Foswiki::Infix::Parser | ||||
6 | |||||
7 | A simple stack-based parser that parses infix expressions with nonary, | ||||
8 | unary and binary operators specified using an operator table. | ||||
9 | |||||
10 | Escapes are supported in strings, using backslash. | ||||
11 | |||||
12 | =cut | ||||
13 | |||||
14 | package Foswiki::Infix::Parser; | ||||
15 | |||||
16 | 2 | 46µs | 2 | 71µs | # spent 48µs (26+23) within Foswiki::Infix::Parser::BEGIN@16 which was called:
# once (26µs+23µs) by Foswiki::Query::Parser::BEGIN@17 at line 16 # spent 48µs making 1 call to Foswiki::Infix::Parser::BEGIN@16
# spent 23µs making 1 call to strict::import |
17 | 2 | 45µs | 2 | 34µs | # spent 25µs (16+9) within Foswiki::Infix::Parser::BEGIN@17 which was called:
# once (16µs+9µs) by Foswiki::Query::Parser::BEGIN@17 at line 17 # spent 25µs making 1 call to Foswiki::Infix::Parser::BEGIN@17
# spent 9µs making 1 call to warnings::import |
18 | 2 | 46µs | 2 | 62µs | # spent 39µs (16+23) within Foswiki::Infix::Parser::BEGIN@18 which was called:
# once (16µs+23µs) by Foswiki::Query::Parser::BEGIN@17 at line 18 # spent 39µs making 1 call to Foswiki::Infix::Parser::BEGIN@18
# spent 23µs making 1 call to Assert::import |
19 | 2 | 68µs | 2 | 626µs | # spent 327µs (29+298) within Foswiki::Infix::Parser::BEGIN@19 which was called:
# once (29µs+298µs) by Foswiki::Query::Parser::BEGIN@17 at line 19 # spent 327µs making 1 call to Foswiki::Infix::Parser::BEGIN@19
# spent 298µs making 1 call to Error::import |
20 | 2 | 186µs | 1 | 522µs | # spent 522µs (424+99) within Foswiki::Infix::Parser::BEGIN@20 which was called:
# once (424µs+99µs) by Foswiki::Query::Parser::BEGIN@17 at line 20 # spent 522µs making 1 call to Foswiki::Infix::Parser::BEGIN@20 |
21 | 2 | 2.36ms | 1 | 878µs | # spent 878µs (807+71) within Foswiki::Infix::Parser::BEGIN@21 which was called:
# once (807µs+71µs) by Foswiki::Query::Parser::BEGIN@17 at line 21 # spent 878µs making 1 call to Foswiki::Infix::Parser::BEGIN@21 |
22 | |||||
23 | # Set to 1 for debug | ||||
24 | 518 | 1.55ms | # spent 686µs within Foswiki::Infix::Parser::MONITOR_PARSER which was called 518 times, avg 1µs/call:
# 106 times (108µs+0s) by Foswiki::Infix::Parser::__ANON__[/var/www/foswiki11/lib/Foswiki/Infix/Parser.pm:277] at line 224, avg 1µs/call
# 106 times (105µs+0s) by Foswiki::Infix::Parser::_apply at line 315, avg 992ns/call
# 83 times (228µs+0s) by Foswiki::Infix::Parser::_parse at line 219, avg 3µs/call
# 83 times (103µs+0s) by Foswiki::Infix::Parser::_parse at line 290, avg 1µs/call
# 81 times (90µs+0s) by Foswiki::Infix::Parser::__ANON__[/var/www/foswiki11/lib/Foswiki/Infix/Parser.pm:277] at line 251, avg 1µs/call
# 58 times (50µs+0s) by Foswiki::Infix::Parser::__ANON__[/var/www/foswiki11/lib/Foswiki/Infix/Parser.pm:277] at line 233, avg 857ns/call
# once (2µs+0s) by Foswiki::Infix::Parser::__ANON__[/var/www/foswiki11/lib/Foswiki/Infix/Parser.pm:277] at line 245 | ||
25 | |||||
26 | =begin TML | ||||
27 | |||||
28 | ---++ new($client_class, \%options) -> parser object | ||||
29 | |||||
30 | Creates a new infix parser. Operators must be added for it to be useful. | ||||
31 | |||||
32 | The tokeniser matches tokens in the following order: operators, | ||||
33 | quotes (" and '), numbers, words, brackets. If you have any overlaps (e.g. | ||||
34 | an operator '<' and a bracket operator '<<') then the first choice | ||||
35 | will match. | ||||
36 | |||||
37 | =$client_class= needs to be the _name_ of a _package_ that supports the | ||||
38 | following two functions: | ||||
39 | * =newLeaf($val, $type)= - create a terminal. $type will be: | ||||
40 | 1 if the terminal matched the =words= specification (see below). | ||||
41 | 2 if it is a number matched the =numbers= specification (see below) | ||||
42 | 3 if it is a quoted string | ||||
43 | * =newNode($op, @params) - create a new operator node. @params | ||||
44 | is a variable-length list of parameters, left to right. $op | ||||
45 | is a reference to the operator hash in the \@opers list. | ||||
46 | These functions should throw Error::Simple in the event of errors. | ||||
47 | Foswiki::Infix::Node is such a class, ripe for subclassing. | ||||
48 | |||||
49 | The remaining parameters are named, and specify options that affect the | ||||
50 | behaviour of the parser: | ||||
51 | 1 =words=>qr//= - should be an RE specifying legal words (unquoted | ||||
52 | terminals that are not operators i.e. names and numbers). By default | ||||
53 | this is =\w+=. | ||||
54 | It's ok if operator names match this RE; operators always have precedence | ||||
55 | over atoms. | ||||
56 | 2 =numbers=>qr//= - should be an RE specifying legal numbers (unquoted | ||||
57 | terminals that are not operators or words). By default | ||||
58 | this is =qr/[+-]?(?:\d+\.\d+|\d+\.|\.\d+|\d+)(?:[eE][+-]?\d+)?/=, | ||||
59 | which matches integers and floating-point numbers. Number | ||||
60 | matching always takes precedence over word matching (i.e. "1xy" will | ||||
61 | be parsed as a number followed by a word. A typical usage of this option | ||||
62 | is when you only want to recognise integers, in which case you would set | ||||
63 | this to =numbers => qr/\d+/=. | ||||
64 | |||||
65 | =cut | ||||
66 | |||||
67 | # spent 61µs within Foswiki::Infix::Parser::new which was called 3 times, avg 20µs/call:
# 3 times (61µs+0s) by Foswiki::Query::Parser::new at line 41 of /var/www/foswiki11/lib/Foswiki/Query/Parser.pm, avg 20µs/call | ||||
68 | 3 | 3µs | my ( $class, $options ) = @_; | ||
69 | |||||
70 | 3 | 33µs | my $this = bless( | ||
71 | { | ||||
72 | client_class => $options->{nodeClass}, | ||||
73 | operators => [], | ||||
74 | initialised => 0, | ||||
75 | }, | ||||
76 | $class | ||||
77 | ); | ||||
78 | |||||
79 | 3 | 11µs | $this->{numbers} = | ||
80 | defined( $options->{numbers} ) | ||||
81 | ? $options->{numbers} | ||||
82 | : qr/[+-]?(\d+\.\d+|\d+\.|\.\d+|\d+)([eE][+-]?\d+)?/; | ||||
83 | |||||
84 | 3 | 4µs | $this->{words} = | ||
85 | defined( $options->{words} ) | ||||
86 | ? $options->{words} | ||||
87 | : qr/\w+/; | ||||
88 | |||||
89 | 3 | 19µs | return $this; | ||
90 | } | ||||
91 | |||||
92 | =begin TML | ||||
93 | |||||
94 | ---++ ObjectMethod finish() | ||||
95 | Break circular references. | ||||
96 | |||||
97 | =cut | ||||
98 | |||||
99 | # spent 2µs within Foswiki::Infix::Parser::finish which was called:
# once (2µs+0s) by Foswiki::Search::finish at line 69 of /var/www/foswiki11/lib/Foswiki/Search.pm | ||||
100 | 1 | 6µs | my $self = shift; | ||
101 | |||||
102 | } | ||||
103 | |||||
104 | =begin TML | ||||
105 | |||||
106 | ---++ ObjectMethod addOperator(\%oper) | ||||
107 | Add an operator to the parser. | ||||
108 | |||||
109 | =\%oper= is a hash (or an object), containing the following fields: | ||||
110 | * =name= - operator string | ||||
111 | * =prec= - operator precedence, positive non-zero integer. | ||||
112 | Larger number => higher precedence. | ||||
113 | * =arity= - set to 1 if this operator is unary, 2 for binary. Arity 0 | ||||
114 | is legal, should you ever need it. | ||||
115 | * =close= - used with bracket operators. =name= should be the open | ||||
116 | bracket string, and =close= the close bracket. The existance of =close= | ||||
117 | marks this as a bracket operator. | ||||
118 | * =casematters== - indicates that the parser should check case in the | ||||
119 | operator name (i.e. treat 'AND' and 'and' as different). | ||||
120 | By default operators are case insensitive. *Note* that operator | ||||
121 | names must be caselessly unique i.e. you can't define 'AND' and 'and' | ||||
122 | as different operators in the same parser. Does not affect the | ||||
123 | interpretation of non-operator terminals (names). | ||||
124 | Other fields in the hash can be used for other purposes; the parse tree | ||||
125 | generated by this parser will point to the hashes passed to this function. | ||||
126 | |||||
127 | Field names in the hash starting with =InfixParser_= are reserved for use | ||||
128 | by the parser. | ||||
129 | |||||
130 | =cut | ||||
131 | |||||
132 | # spent 208µs within Foswiki::Infix::Parser::addOperator which was called 65 times, avg 3µs/call:
# 57 times (175µs+0s) by Foswiki::Query::Parser::new at line 47 of /var/www/foswiki11/lib/Foswiki/Query/Parser.pm, avg 3µs/call
# 8 times (32µs+0s) by Foswiki::If::Parser::new at line 31 of /var/www/foswiki11/lib/Foswiki/If/Parser.pm, avg 4µs/call | ||||
133 | 65 | 40µs | my ( $this, $op ) = @_; | ||
134 | 65 | 56µs | push( @{ $this->{operators} }, $op ); | ||
135 | 65 | 182µs | $this->{initialised} = 0; | ||
136 | } | ||||
137 | |||||
138 | # Initialise on demand before a first parse | ||||
139 | # spent 947µs within Foswiki::Infix::Parser::_initialise which was called 83 times, avg 11µs/call:
# 83 times (947µs+0s) by Foswiki::Infix::Parser::parse at line 203, avg 11µs/call | ||||
140 | 83 | 32µs | my $this = shift; | ||
141 | |||||
142 | 83 | 326µs | return if $this->{initialised}; | ||
143 | |||||
144 | # Build operator lists | ||||
145 | 3 | 800ns | my @stdOpsRE; | ||
146 | 3 | 400ns | my @bracketOpsRE; | ||
147 | 3 | 4µs | foreach my $op ( @{ $this->{operators} } ) { | ||
148 | |||||
149 | # Build a RE for the operator. Note that operators | ||||
150 | # that end in \w are terminated with \b | ||||
151 | 65 | 35µs | my $opre = quotemeta( $op->{name} ); | ||
152 | 65 | 84µs | $opre .= ( $op->{name} =~ /\w$/ ) ? '\b' : ''; | ||
153 | 65 | 31µs | if ( $op->{casematters} ) { | ||
154 | 4 | 21µs | $op->{InfixParser_RE} = qr/$opre/; | ||
155 | } | ||||
156 | else { | ||||
157 | 61 | 296µs | $op->{InfixParser_RE} = qr/$opre/i; | ||
158 | } | ||||
159 | 65 | 51µs | if ( defined( $op->{close} ) ) { | ||
160 | |||||
161 | # bracket op | ||||
162 | 6 | 14µs | $this->{bracket_ops}->{ lc( $op->{name} ) } = $op; | ||
163 | |||||
164 | 6 | 3µs | $opre = quotemeta( $op->{close} ); | ||
165 | 6 | 7µs | $opre .= ( $op->{close} =~ /\w$/ ) ? '\b' : ''; | ||
166 | 6 | 3µs | if ( $op->{casematters} ) { | ||
167 | $op->{InfixParser_closeRE} = qr/$opre/; | ||||
168 | } | ||||
169 | else { | ||||
170 | 6 | 23µs | $op->{InfixParser_closeRE} = qr/$opre/i; | ||
171 | } | ||||
172 | 6 | 4µs | push( @bracketOpsRE, $op->{InfixParser_RE} ); | ||
173 | } | ||||
174 | else { | ||||
175 | 59 | 82µs | $this->{standard_ops}->{ lc( $op->{name} ) } = $op; | ||
176 | 59 | 30µs | push( @stdOpsRE, $op->{InfixParser_RE} ); | ||
177 | } | ||||
178 | } | ||||
179 | |||||
180 | # Build regular expression of all standard operators. | ||||
181 | 3 | 13µs | $this->{standard_op_REs} = join( '|', @stdOpsRE ); | ||
182 | |||||
183 | # and repeat for bracket operators | ||||
184 | 3 | 4µs | $this->{bracket_op_REs} = join( '|', @bracketOpsRE ); | ||
185 | |||||
186 | 3 | 20µs | $this->{initialised} = 1; | ||
187 | } | ||||
188 | |||||
189 | =begin TML | ||||
190 | |||||
191 | ---++ ObjectMethod parse($string) -> $parseTree | ||||
192 | Parses =$string=, calling =newLeaf= and =newNode= in the client class | ||||
193 | as necessary to create a parse tree. Returns the result of calling =newNode= | ||||
194 | on the root of the parse. | ||||
195 | |||||
196 | Throws Foswiki::Infix::Error in the event of parse errors. | ||||
197 | |||||
198 | =cut | ||||
199 | |||||
200 | # spent 33.5ms (889µs+32.6) within Foswiki::Infix::Parser::parse which was called 83 times, avg 403µs/call:
# 41 times (347µs+22.2ms) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki/Macros/IF.pm:43] at line 34 of /var/www/foswiki11/lib/Foswiki/Macros/IF.pm, avg 549µs/call
# 41 times (522µs+9.85ms) by Foswiki::Search::__ANON__[/var/www/foswiki11/lib/Foswiki/Search.pm:133] at line 132 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 253µs/call
# once (20µs+566µs) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki/Macros/QUERY.pm:56] at line 52 of /var/www/foswiki11/lib/Foswiki/Macros/QUERY.pm | ||||
201 | 83 | 72µs | my ( $this, $expr ) = @_; | ||
202 | 83 | 39µs | my $data = $expr; | ||
203 | 83 | 185µs | 83 | 947µs | $this->_initialise(); # spent 947µs making 83 calls to Foswiki::Infix::Parser::_initialise, avg 11µs/call |
204 | 83 | 420µs | 83 | 31.6ms | return _parse( $this, $expr, \$data ); # spent 31.6ms making 83 calls to Foswiki::Infix::Parser::_parse, avg 381µs/call |
205 | } | ||||
206 | |||||
207 | # Simple stack parser, after Knuth | ||||
208 | # spent 31.6ms (4.87+26.8) within Foswiki::Infix::Parser::_parse which was called 83 times, avg 381µs/call:
# 83 times (4.87ms+26.8ms) by Foswiki::Infix::Parser::parse at line 204, avg 381µs/call | ||||
209 | 83 | 86µs | my ( $this, $expr, $input, $term ) = @_; | ||
210 | |||||
211 | 83 | 205µs | throw Foswiki::Infix::Error("Empty expression") | ||
212 | unless defined($expr) && $expr =~ /\S/; | ||||
213 | |||||
214 | 83 | 40µs | my @opers = (); | ||
215 | 83 | 22µs | my @opands = (); | ||
216 | |||||
217 | 83 | 29µs | $input ||= \$expr; | ||
218 | |||||
219 | 83 | 249µs | 83 | 228µs | print STDERR "Parse: $$input\n" if MONITOR_PARSER; # spent 228µs making 83 calls to Foswiki::Infix::Parser::MONITOR_PARSER, avg 3µs/call |
220 | # spent 19.8ms (13.4+6.36) within Foswiki::Infix::Parser::__ANON__[/var/www/foswiki11/lib/Foswiki/Infix/Parser.pm:277] which was called 83 times, avg 238µs/call:
# 83 times (13.4ms+6.36ms) by Error::subs::try at line 419 of Error.pm, avg 238µs/call | ||||
221 | 83 | 191µs | while ( $$input =~ /\S/ ) { | ||
222 | 246 | 2.32ms | if ( $$input =~ s/^\s*($this->{standard_op_REs})// ) { | ||
223 | 106 | 99µs | my $opname = $1; | ||
224 | 106 | 137µs | 106 | 108µs | print STDERR "Tok: op '$opname'\n" if MONITOR_PARSER; # spent 108µs making 106 calls to Foswiki::Infix::Parser::MONITOR_PARSER, avg 1µs/call |
225 | 106 | 171µs | my $op = $this->{standard_ops}->{ lc($opname) }; | ||
226 | 106 | 140µs | 106 | 120µs | ASSERT( $op, $opname ) if DEBUG; # spent 120µs making 106 calls to Assert::ASSERTS_OFF, avg 1µs/call |
227 | 106 | 269µs | 106 | 636µs | _apply( $this, $op->{prec}, \@opers, \@opands ); # spent 636µs making 106 calls to Foswiki::Infix::Parser::_apply, avg 6µs/call |
228 | 106 | 98µs | push( @opers, $op ); | ||
229 | } | ||||
230 | elsif ( $$input =~ s/^\s*(['"])(|.*?[^\\])\1// ) { | ||||
231 | 58 | 52µs | my $q = $1; | ||
232 | 58 | 34µs | my $val = $2; | ||
233 | 58 | 74µs | 58 | 50µs | print STDERR "Tok: qs '$q'\n" if MONITOR_PARSER; # spent 50µs making 58 calls to Foswiki::Infix::Parser::MONITOR_PARSER, avg 857ns/call |
234 | |||||
235 | # Handle escaped characters in the string. This is where | ||||
236 | # expansions such as \n are handled | ||||
237 | $val =~ | ||||
238 | 58 | 145µs | s/(?<!\\)\\(0[0-7]{2}|x[a-fA-F0-9]{2}|x{[a-fA-F0-9]+}|n|t|\\|$q)/eval('"\\'.$1.'"')/ge; | ||
239 | 58 | 219µs | 58 | 962µs | push( @opands, # spent 962µs making 58 calls to Foswiki::Query::Node::newLeaf, avg 17µs/call |
240 | $this->{client_class} | ||||
241 | ->newLeaf( $val, $Foswiki::Infix::Node::STRING ) ); | ||||
242 | } | ||||
243 | elsif ( $$input =~ s/^\s*($this->{numbers})// ) { | ||||
244 | 1 | 4µs | my $val = 0 + $1; | ||
245 | 1 | 2µs | 1 | 2µs | print STDERR "Tok: number '$val'\n" if MONITOR_PARSER; # spent 2µs making 1 call to Foswiki::Infix::Parser::MONITOR_PARSER |
246 | 1 | 12µs | 1 | 43µs | push( @opands, # spent 43µs making 1 call to Foswiki::Query::Node::newLeaf |
247 | $this->{client_class} | ||||
248 | ->newLeaf( $val, $Foswiki::Infix::Node::NUMBER ) ); | ||||
249 | } | ||||
250 | elsif ( $$input =~ s/^\s*($this->{words})// ) { | ||||
251 | 81 | 127µs | 81 | 90µs | print STDERR "Tok: word '$1'\n" if MONITOR_PARSER; # spent 90µs making 81 calls to Foswiki::Infix::Parser::MONITOR_PARSER, avg 1µs/call |
252 | 81 | 96µs | my $val = $1; | ||
253 | 81 | 449µs | 81 | 2.51ms | push( @opands, # spent 2.51ms making 81 calls to Foswiki::Query::Node::newLeaf, avg 31µs/call |
254 | $this->{client_class} | ||||
255 | ->newLeaf( $val, $Foswiki::Infix::Node::NAME ) ); | ||||
256 | } | ||||
257 | elsif ( $$input =~ s/^\s*($this->{bracket_op_REs})// ) { | ||||
258 | my $opname = $1; | ||||
259 | print STDERR "Tok: open bracket $opname\n" if MONITOR_PARSER; | ||||
260 | my $op = $this->{bracket_ops}->{ lc($opname) }; | ||||
261 | ASSERT($op) if DEBUG; | ||||
262 | _apply( $this, $op->{prec}, \@opers, \@opands ); | ||||
263 | push( @opers, $op ); | ||||
264 | push( @opands, | ||||
265 | $this->_parse( $expr, $input, $op->{InfixParser_closeRE} ) | ||||
266 | ); | ||||
267 | } | ||||
268 | elsif ( defined($term) && $$input =~ s/^\s*$term// ) { | ||||
269 | print STDERR "Tok: close bracket $term\n" if MONITOR_PARSER; | ||||
270 | last; | ||||
271 | } | ||||
272 | else { | ||||
273 | throw Foswiki::Infix::Error( 'Syntax error', $expr, $$input ); | ||||
274 | } | ||||
275 | } | ||||
276 | 83 | 5.64ms | 83 | 1.84ms | _apply( $this, 0, \@opers, \@opands ); # spent 1.84ms making 83 calls to Foswiki::Infix::Parser::_apply, avg 22µs/call |
277 | } | ||||
278 | catch Error::Simple with { | ||||
279 | |||||
280 | # Catch errors thrown during the tree building process | ||||
281 | throw Foswiki::Infix::Error( shift, $expr, $$input ); | ||||
282 | 83 | 3.33ms | 249 | 461µs | }; # spent 350µs making 83 calls to Error::catch, avg 4µs/call
# spent 111µs making 83 calls to Error::subs::with, avg 1µs/call
# spent 26.0ms making 83 calls to Error::subs::try, avg 313µs/call, recursion: max depth 4, sum of overlapping time 26.0ms |
283 | 83 | 54µs | throw Foswiki::Infix::Error( 'Missing operator', $expr, $$input ) | ||
284 | unless scalar(@opands) == 1; | ||||
285 | throw Foswiki::Infix::Error( | ||||
286 | 83 | 25µs | 'Excess operators (' . join( ' ', map { $_->{name} } @opers ) . ')', | ||
287 | $expr, $$input ) | ||||
288 | if scalar(@opers); | ||||
289 | 83 | 39µs | my $result = pop(@opands); | ||
290 | 83 | 149µs | 83 | 103µs | print STDERR "Return " . $result->stringify() . "\n" if MONITOR_PARSER; # spent 103µs making 83 calls to Foswiki::Infix::Parser::MONITOR_PARSER, avg 1µs/call |
291 | 83 | 248µs | return $result; | ||
292 | } | ||||
293 | |||||
294 | # Apply ops on the stack while their precedence is higher than $prec | ||||
295 | # For each operator on the stack with precedence >= $prec, pop the | ||||
296 | # required number of operands, construct a new parse node and push | ||||
297 | # the node back onto the operand stack. | ||||
298 | # spent 2.48ms (1.91+574µs) within Foswiki::Infix::Parser::_apply which was called 189 times, avg 13µs/call:
# 106 times (536µs+100µs) by Foswiki::Infix::Parser::__ANON__[/var/www/foswiki11/lib/Foswiki/Infix/Parser.pm:277] at line 227, avg 6µs/call
# 83 times (1.37ms+474µs) by Foswiki::Infix::Parser::__ANON__[/var/www/foswiki11/lib/Foswiki/Infix/Parser.pm:277] at line 276, avg 22µs/call | ||||
299 | 189 | 141µs | my ( $this, $prec, $opers, $opands ) = @_; | ||
300 | |||||
301 | 189 | 8.21ms | while (scalar(@$opers) | ||
302 | && $opers->[-1]->{prec} >= $prec | ||||
303 | && scalar(@$opands) >= $opers->[-1]->{arity} ) | ||||
304 | { | ||||
305 | 106 | 58µs | my $op = pop(@$opers); | ||
306 | 106 | 34µs | my $arity = $op->{arity}; | ||
307 | 106 | 19µs | my @prams; | ||
308 | 106 | 65µs | while ( $arity-- ) { | ||
309 | 163 | 88µs | unshift( @prams, pop(@$opands) ); | ||
310 | |||||
311 | # Should never get thrown, but just in case... | ||||
312 | 163 | 91µs | throw Foswiki::Infix::Error("Missing operand to '$op->{name}'") | ||
313 | unless $prams[0]; | ||||
314 | } | ||||
315 | 106 | 153µs | 106 | 105µs | if (MONITOR_PARSER) { # spent 105µs making 106 calls to Foswiki::Infix::Parser::MONITOR_PARSER, avg 992ns/call |
316 | print STDERR "Apply $op->{name}(" | ||||
317 | . join( ', ', map { $_->stringify() } @prams ) . ")\n"; | ||||
318 | } | ||||
319 | 106 | 458µs | 106 | 468µs | push( @$opands, $this->{client_class}->newNode( $op, @prams ) ); # spent 468µs making 106 calls to Foswiki::Infix::Node::newNode, avg 4µs/call |
320 | } | ||||
321 | } | ||||
322 | |||||
323 | 1 | 4µs | 1; | ||
324 | __END__ |