/
ConstantFolder.pm
53 lines (50 loc) · 1.95 KB
/
ConstantFolder.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
42
43
44
45
46
47
48
49
50
51
52
53
# Quick and dirty constant folder; probably needs a bunch more work.
class Perl6::ConstantFolder {
# Tries to fold. Throws if it's not possible.
method fold($expr, $scope, $world) {
if $expr.has_compile_time_value {
# It's already got a compile time value, just hand it back.
$expr
}
elsif nqp::istype($expr, QAST::Op) && $expr.name && $expr.op eq 'call' {
# Potentially foldable call. Try to get compile time args (which
# my involve recursively folding).
my @args;
for @($expr) {
my $arg := self.fold($_, $scope, $world);
if $arg.has_compile_time_value {
@args.push($arg.compile_time_value)
}
else {
nqp::die("No compile time value obtainable for argument to " ~ $expr.name);
}
}
# Got constant or folded arguments. Look for symbol and invoke it with
# the arguments.
my $routine := self.locate_symbol($scope, $expr.name);
my $result := $routine(|@args);
# Add folded symbol into the world (which'll return a PAST ref to it).
$world.add_constant_folded_result(pir::nqp_decontainerize__PP($result))
}
else {
nqp::die("No compile time value obtainable");
}
}
# Look for a symbol needed in the constant folding.
method locate_symbol($scope, $name) {
my $block := $scope;
while $block {
my %sym := $block.symbol($name);
if +%sym {
if nqp::existskey(%sym, 'value') {
return %sym<value>;
}
else {
nqp::die("No compile time value for $name");
}
}
$block := $block<outer>;
}
nqp::die("Could not locate compile time $name");
}
}