File Coverage

blib/lib/Language/P/Assembly.pm
Criterion Covered Total %
statement 64 71 90.1
branch 29 40 72.5
condition 10 15 66.6
subroutine 14 17 82.3
pod 3 7 42.8
total 120 150 80.0


line stmt bran cond sub pod time code
1             package Language::P::Assembly;
2              
3 37     37   229 use strict;
  37         80  
  37         1251  
4 37     37   449 use warnings;
  37         85  
  37         903  
5 37     37   202 use Exporter; *import = \&Exporter::import;
  37         89  
  37         15929  
6              
7             our @EXPORT_OK = qw(label literal opcode opcode_n opcode_m opcode_nm);
8             our %EXPORT_TAGS =
9             ( all => \@EXPORT_OK,
10             );
11              
12             =head1 NAME
13              
14             Language::P::Assembly - representation for generic assembly-like language
15              
16             =head1 DESCRIPTION
17              
18             Abstract representation for assembly-like languages, used internally
19             by backends.
20              
21             =head1 FUNCTIONS
22              
23             =cut
24              
25 4159     4159 0 13625 sub i { Language::P::Assembly::Instruction->new( $_[0] ) }
26              
27             =head2 label
28              
29             my $l = label( 'lbl1' );
30              
31             A label, rendered as a left-aligned C.
32              
33             =cut
34              
35             sub label {
36 770     770 1 5442 my( $label ) = @_;
37              
38 770         3419 return i { label => $label,
39             };
40             }
41              
42             =head2 literal
43              
44             my $l = literal( "foo: eq 123" );
45              
46             A string rendered as-is in the final output.
47              
48             =cut
49              
50             sub literal {
51 0     0 1 0 my( $string ) = @_;
52              
53 0         0 return i { literal => $string,
54             };
55             }
56              
57             =head2 opcode
58              
59             my $o = opcode( 'add', $res, $op1, $op2 );
60              
61             A generic opcode with operands, rendered as C< add arg1, arg2, ...>.
62              
63             =cut
64              
65             sub opcode {
66 0     0 1 0 my( $name, @parameters ) = @_;
67              
68 0 0       0 return i { opcode => $name,
69             parameters => @parameters ? \@parameters : undef,
70             };
71             }
72              
73             sub opcode_n {
74 1831     1831 0 9264 my( $number, @parameters ) = @_;
75              
76 1831 100       8136 return i { opcode_n => $number,
77             parameters => @parameters ? \@parameters : undef,
78             };
79             }
80              
81             sub opcode_m {
82 0     0 0 0 my( $name, %attributes ) = @_;
83              
84 0 0       0 return i { opcode => $name,
85             attributes => %attributes ? \%attributes : undef,
86             };
87             }
88              
89             sub opcode_nm {
90 1558     1558 0 9765 my( $number, %attributes ) = @_;
91              
92 1558 100       6890 return i { opcode_n => $number,
93             attributes => %attributes ? \%attributes : undef,
94             };
95             }
96              
97             package Language::P::Assembly::Instruction;
98              
99 37     37   381 use strict;
  37         91  
  37         1326  
100 37     37   223 use warnings;
  37         82  
  37         1335  
101 37     37   198 use base qw(Class::Accessor::Fast);
  37         70  
  37         3901  
102              
103             __PACKAGE__->mk_ro_accessors( qw(label literal opcode opcode_n
104             parameters attributes) );
105              
106 37     37   226 use Scalar::Util qw(blessed);
  37         182  
  37         4693  
107 37     37   232 use Language::P::ParseTree qw(VALUE_SCALAR VALUE_ARRAY VALUE_HASH);
  37         77  
  37         29229  
108              
109             my %sigil_to_name =
110             ( VALUE_SCALAR() => 'scalar',
111             VALUE_ARRAY() => 'array',
112             VALUE_HASH() => 'hash',
113             );
114              
115             sub _p {
116 1023     1023   2298 my( $self, $arg, $index, $number_to_name, $attributes ) = @_;
117              
118 1023 100       3665 if( blessed( $arg ) ) {
119 484 100       2819 return $arg->start_label
120             if $arg->isa( 'Language::P::Intermediate::BasicBlock' );
121 255 100       1234 return '(' . substr( $arg->as_string( $number_to_name, $attributes ), 2, -1 ) . ')'
122             if $arg->isa( 'Language::P::Assembly::Instruction' );
123 5 100       47 return $sigil_to_name{$arg->sigil} . '(' . $arg->name . ')'
124             if $arg->isa( 'Language::P::ParseTree::LexicalDeclaration' );
125 2 50       14 return 'anoncode'
126             if $arg->isa( 'Language::P::Intermediate::Code' );
127             }
128 539 50 66     3788 if( $self->{opcode_n} && defined $index && $attributes
      66        
      66        
129             && (my $positional = $attributes->{$self->{opcode_n}}{positional}) ) {
130 233         380 my $type = $positional->[$index];
131              
132 233 100 66     668 if( $type && $type eq 's' ) {
133 12         64 ( my $v = $arg ) =~ s/([^\x20-\x7f])/sprintf "\\x%02x", ord $1/eg;
  6         52  
134              
135 12         68 return qq{"$v"};
136             }
137             }
138              
139 527         2015 return $arg;
140             }
141              
142             sub as_string {
143 1006     1006   7191 my( $self, $number_to_name, $attributes ) = @_;
144              
145 1006 50       2197 return $self->{literal} . "\n" if defined $self->{literal};
146              
147 1006 100       2360 my $str = defined $self->{label} ? $self->{label} . ':' : ' ';
148              
149 1006 100 66     4754 return $str . "\n" unless defined $self->{opcode}
150             || defined $self->{opcode_n};
151 798         937 $str .= ' ';
152              
153 798 50       2205 if( defined $self->{opcode} ) {
    50          
154 0         0 $str .= $self->{opcode};
155             } elsif( defined $self->{opcode_n} ) {
156 798         1812 $str .= $number_to_name->{$self->{opcode_n}};
157             }
158              
159 798 100       1643 if( $self->{attributes} ) {
160 236 50       255 die "Can't happen" unless %{$self->{attributes}};
  236         594  
161 388         1384 $str .= ' ' . join ', ',
162 236         654 map { "$_=" . _p( $self, $self->{attributes}{$_}, undef, $number_to_name, $attributes ) }
163 236         325 keys %{$self->{attributes}};
164             }
165              
166 798 100       2393 if( $self->{parameters} ) {
167 441 50       456 die "Can't happen" unless @{$self->{parameters}};
  441         1042  
168 441         637 my $i = 0;
169 441         1339 $str .= ' ' . join ', ', map _p( $self, $_, $i++, $number_to_name, $attributes ),
170 441         527 @{$self->{parameters}};
171             }
172              
173 798         3987 return $str . "\n";
174             }
175              
176             1;