-
Notifications
You must be signed in to change notification settings - Fork 7
/
Interpolation.pm
41 lines (33 loc) · 1.38 KB
/
Interpolation.pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
use Hitomi::StreamEventKind;
grammar Hitomi::Interpolation::Grammar {
regex TOP { ^ <chunk>* $ }
regex chunk { <plain> || <expr> }
regex plain { [<!after '$'> .]+ }
regex expr { '$' [ <identifier> | <block> ] }
regex ident { <.alpha> \w* }
regex identifier { <.ident> [ <.apostrophe> <.ident> ]* }
token apostrophe { <[ ' \- ]> }
regex block { '{' <content> '}' }
regex content { <-[{}]>+ }
}
# Note: It _is_ possible for the above grammar to fail, even though it's
# probably not very desirable that it can. An example of a failing
# input is '$'. The way to fix this would likely be (1) see what
# Genshi does about broken input, (2) write Hitomi tests to do the
# same, (3) improve the grammar.
sub interpolate($text, $filepath, $lineno = -1, $offset = 0,
$lookup = 'strict') {
# TODO: Make it impossible to fail here. See the above note.
return $text
unless Hitomi::Interpolation::Grammar.parse($text);
return gather for @($<chunk> // []) -> $chunk {
my $pos = [$filepath, $lineno, $offset];
if $chunk<plain> -> $plain {
take [Hitomi::StreamEventKind::text, ~$plain, $pos];
}
elsif $chunk<expr> -> $expr {
my $data = $expr<block> ?? $expr<block><content> !! $expr;
take [Hitomi::StreamEventKind::expr, ~$data, $pos];
}
}
}