1 # Copyright (C) 2008, The Perl Foundation.
6 PHP 5.3 has four kinds of literal strings.
12 Neither variable nor backslash interpolation, besides B<\'> and B<\\> is done within single quotes.
13 Single quotes need to be escaped with a backslash in order to be not taken for the delimiter.
14 A backslash escapes a following backslash.
15 A literal backslash needs to be escaped at end of string, as otherwise the delimiting single quote
16 would be recognised as a literal single quote.
17 In contrast to Perl 5, backslashes that preceede any other character are literal.
22 \n, \r, \t, \v, \f, \\, \$, \"
25 Charactes can alse be written in octal notation, \[0-7]{1,3},
26 and hexadecimal notation, \x[0-9A-Fa-f]{1,2}.
27 The octal notation allows to specify values greater 256. In theses
28 cases the value is taken as mod 256.
34 Variables are interpolated.
38 Double quotes are literal.
39 The backslashes before a double quote are literal.
40 Unlike in Perl 5, the newline before the delimiter is not part of the string.
44 A heredoc with single quotes.
47 $example = <<<'EXAMPLE'
48 Variables are not interpolated.
52 Single quotes are literal.
53 Backslashes are literal.
54 Unlike in Perl 5, the newline before the delimiter is not part of the string.
58 .namespace ['Pipp::Grammar']
60 ## called from code in grammar.pg
61 .sub 'quote_expression' :method
63 .param pmc options :slurpy :named
65 ## create a new match object
69 (mob, pos, target) = self.'new'(self)
73 action = options['action']
75 ## set up options based on flags
76 .local pmc flagarray, iter
77 flagarray = split ' ', flags
78 iter = new 'Iterator', flagarray
80 unless iter goto iter_end
83 oname = substr oname, 1 # remove the leading colon
85 if oname == 'qq' goto opt_qq
88 options['s'] = 1 # interpolate variables
89 options['c'] = 1 # interpolate stuff in '{ }', when there is a $ right after the '{'
90 options['b'] = 1 # Interpolate \n, \t, etc. 'b' stands for backslash
91 options['q'] = 1 # Interpolate \\, \q and \' (or whatever)
95 ## there is no heredoc-support yet, so the delimiter are either single or double quotes
96 .local string start, stop
97 start = substr target, pos, 1
99 options['stop'] = stop
104 lastpos = length target
108 ## handle word parsing
110 ## set up escapes based on flags
111 .local string escapes
114 unless $I0 goto escape_s_done
118 unless $I0 goto escape_c_done
122 options['escapes'] = escapes
124 .local pmc quote_concat
125 quote_concat = new 'ResizablePMCArray'
129 $S0 = substr target, pos, 1
130 if $S0 == stop goto word_succeed
131 if pos >= lastpos goto fail
136 $P0 = mob.'quote_concat'(options)
138 push quote_concat, $P0
143 mob[key] = quote_concat
148 if null action goto succeed_done
149 $I0 = can action, 'quote_expression'
150 unless $I0 goto succeed_done
151 action.'quote_expression'(mob, key)
160 .sub 'quote_concat' :method
163 ## create a new match object
167 (mob, pos, target) = self.'new'(self)
169 ## determine pos, lastpos
172 stop = options['stop']
173 lastpos = length target
176 .local string escapes
177 escapes = options['escapes']
179 .local pmc quote_term
180 quote_term = new 'ResizablePMCArray'
184 $P0 = mob.'quote_term'(options)
188 if pos > lastpos goto fail
189 $S0 = substr target, pos, 1
190 if $S0 == stop goto succeed
193 ## save the array of captured terms
194 mob['quote_term'] = quote_term
196 ## call any related {*} actions
198 action = options['action']
199 if null action goto succeed_done
200 $I0 = can action, 'quote_concat'
201 unless $I0 goto succeed_done
202 action.'quote_concat'(mob)
211 .sub 'quote_term' :method
215 action = options['action']
220 (mob, pos, target) = self.'new'(self)
222 .local int dollar_is_literal
223 dollar_is_literal = 0
225 .local string leadchar, escapes
226 escapes = options['escapes']
227 leadchar = substr target, pos, 1
228 $I0 = index escapes, leadchar
229 if $I0 < 0 goto term_literal
230 if leadchar == '$' goto term_scalar
231 if leadchar == '{' goto term_closure
234 $P0 = mob.'quote_literal'(options, dollar_is_literal)
237 mob['quote_literal'] = $P0
244 $P0 = mob.'var'('action'=>action)
245 unless $P0 goto var_did_not_match
251 dollar_is_literal = 1
256 $P0 = mob.'curly_interpolation'('action'=>action)
257 unless $P0 goto term_literal
259 key = 'curly_interpolation'
265 if null action goto succeed_done
266 $I0 = can action, 'quote_term'
267 unless $I0 goto succeed_done
268 action.'quote_term'(mob, key)
278 .sub 'quote_literal' :method
280 .param int dollar_is_literal
285 (mob, pos, target) = self.'new'(self)
287 .local string stop, stop1
289 stop = options['stop']
290 stop1 = substr stop, 0, 1
291 lastpos = length target
294 .local string escapes
295 .local int optq, optb
296 escapes = options['escapes']
300 .local string literal
303 if pos > lastpos goto fail
304 $S0 = substr target, pos, 1
305 if $S0 == stop goto succeed
308 if pos >= lastpos goto fail
311 .local string litchar
312 litchar = substr target, pos, 1
313 ## if we've reached an escape char, we're done
314 if litchar == '{' goto add_litchar
315 unless dollar_is_literal goto dollar_is_not_a_literal
316 if litchar == '$' goto add_litchar
317 dollar_is_not_a_literal:
318 $I0 = index escapes, litchar
319 if $I0 >= 0 goto succeed
320 ## if this isn't an interpolation, add the char
321 unless optq goto add_litchar
322 if litchar != "\\" goto add_litchar
323 ## okay, we have a backslash, let's process it
324 .local string backchar
326 backchar = substr target, $I0, 1
327 ## handle :q options, \\ and \+stop
328 if backchar == "\\" goto add_backchar
329 if backchar == stop1 goto add_backchar
330 unless optb goto add_litchar
332 $I0 = index "vfnrt\\$\"x0123456789", backchar
333 if $I0 < 0 goto add_backslash_and_backchar
334 if $I0 > 8 goto scan_octal
335 if $I0 == 8 goto scan_hex
336 litchar = substr "\v\f\n\r\t\\$\"", $I0, 1
341 add_backslash_and_backchar:
353 .local int base, decnum, max_digits, cnt_digit
357 pos += 1 # octal digits come right after the '\'
362 pos += 2 # skip the 'x'
364 ## Handle hex and octal escapes.
365 ## The base is either 8 or 16.
366 ## Then loop through the characters
367 ## that follow to compute the decimal value of codepoints,
368 ## and add the codepoints to our literal.
371 $S0 = substr target, pos, 1
373 if cnt_digit > max_digits goto scan_xo_char_end
375 $S0 = substr target, pos, 1
376 $I0 = index '0123456789abcdef0123456789ABCDEF', $S0
377 if $I0 < 0 goto scan_xo_char_end
379 if $I0 >= base goto scan_xo_char_end
383 goto scan_xo_char_loop
391 mob.'result_object'(literal)
395 self.panic('encountered invalid octal digit')
406 # vim: expandtab shiftwidth=4 ft=pir: