root/src/perl6/viv

Revision 23048, 9.0 kB (checked in by lwall, 3 hours ago)

[gimme5] switch back to YAML::Syck till YAML::XS is fixed
[viv] allow input from stdin
[STD] always report worries for now

  • Property svn:mime-type set to text/plain; charset=UTF-8
  • Property svn:eol-style set to native
  • Property svn:executable set to *
Line 
1#!/usr/local/bin/perl
2
3# The start of a gimme5 replacement based on STD parsing.
4#
5use strict;
6use warnings;
7
8use STD;
9use utf8;
10use YAML::XS;
11use feature 'say';
12
13$::ACTIONS = 'Actions';
14my $OPT_pos = 0;
15my $OPT_match = 0;
16my $OPT_log = 0;
17my @did_ws;
18
19sub USAGE {
20    print <<'END';
21viv [switches] filename
22    where switches can be:
23        --ast   spit out an abstract syntax tree (default)
24        --p5    spit out a Perl 5 representation (unimpl)
25        --p6    spit out a Perl 6 representation (partially impl)
26        --pos   include position info in AST
27        --match include match tree info in AST
28        --log   emit debugging info to standard error
29END
30    exit;
31}
32
33
34sub MAIN {
35    my $output = 'ast';
36
37    USAGE() unless @_;
38    while (@_) {
39        last unless $_[0] =~ /^--/;
40        my $switch = shift @_;
41        if ($switch eq '--ast') {
42            $output = 'ast';
43        }
44        elsif ($switch eq '--p5') {
45            $output = 'p5';
46        }
47        elsif ($switch eq '--p6') {
48            $output = 'p6';
49            $OPT_pos = 1;
50        }
51        elsif ($switch eq '--log') {
52            $OPT_log = 1;
53        }
54        elsif ($switch eq '--pos') {
55            $OPT_pos = 1;       # attach position and prior ws len
56        }
57        elsif ($switch eq '--match') {
58            $OPT_match = 1;     # attach match object
59        }
60        elsif ($switch eq '--help') {
61            USAGE();
62        }
63    }
64#    USAGE() unless -r $_[0];
65    my $r;
66    if (@_ and -f $_[0]) {
67        $r = STD->parsefile($_[0])->item;
68    }
69    else {
70        my $prog;
71        {
72            local $/;
73            $prog = <>;
74        }
75        $r = STD->parse($prog)->item;
76    }
77    if ($output eq 'ast') {
78        print Dump($r);
79    }
80    elsif ($output eq 'p6') {
81        print $r->emit_p6;
82    }
83    elsif ($output eq 'p5') {
84        print $r->emit_p5;
85    }
86    else {
87        die "Unknown output mode";
88    }
89}
90
91###################################################################
92
93{ package Actions;
94
95    # Generic ast translation done via autoload
96
97    our $AUTOLOAD;
98    my $SEQ = 1;
99
100    sub AUTOLOAD {
101        my $self = shift;
102        my $match = shift;
103        my $r = hoist($match);
104        (my $class = $AUTOLOAD) =~ s/^Actions/VAST/;
105        gen_class($class);
106        bless $r, $class unless ref($r) =~ /^VAST/;
107        $r->{MATCH} = $match if $OPT_match;
108        $match->{''} = $r;
109    }
110
111    # propagate ->{''} nodes upward
112    # (untransformed STD nodes in output indicate bugs)
113
114    sub hoist {
115        my $node = shift;
116        my $text = $node->text;
117        my %r;
118        for my $k (keys %$node) {
119            my $v = $node->{$k};
120            if ($k eq 'O') {
121                for my $key (keys %$v) {
122                    $r{$key} = $$v{$key};
123                }
124            }
125            elsif ($k eq 'SIGIL') {
126                $r{SIGIL} = $v;
127            }
128            elsif ($k eq '_arity') {
129                $r{ARITY} = $v;
130            }
131            elsif ($k eq '_from') {
132                $r{POS} = $v if $OPT_pos;
133                if (exists $::MEMOS[$v]{'ws'}) {
134                    my $wsstart = $::MEMOS[$v]{'ws'};
135                    $r{WS} = $v - $wsstart if defined $wsstart and $wsstart < $v
136                }
137            }
138            elsif ($k =~ /^[a-zA-Z]/) {
139                if (ref $v eq 'ARRAY') {
140                    my $zyg = [];
141                    for my $z (@$v) {
142                        if (ref $z) {
143                            if (ref $z eq 'ARRAY') {
144                                push @$zyg, $z;
145                            }
146                            elsif (exists $z->{''}) {
147                                push @$zyg, $z->{''};
148                            }
149                        }
150                        else {
151                            push @$zyg, $z;
152                        }
153                    }
154                    $r{$k} = $zyg;
155                    $r{zygs}{$k} = $SEQ++ if @$zyg and $k ne 'sym';
156                }
157                elsif (ref $v) {
158                    if (exists $v->{''}) {
159                        $r{$k} = $v->{''};
160                    }
161                    else {
162                        $r{$k} = $v;
163                    }
164                    $r{zygs}{$k} = $SEQ++;
165                    unless (ref($r{$k}) =~ /^VAST/) {
166                        my $class = "VAST::$k";
167                        gen_class($class);
168                        bless $r{$k}, $class;
169                    }
170                }
171                else {
172                    $r{$k} = $v;
173                }
174            }
175        }
176        $r{TEXT} = $text unless exists $r{zygs};
177        \%r;
178    }
179
180    sub EXPR {
181        my $self = shift;
182        my $match = shift;
183        my $r = hoist($match);
184        (my $class = $r->{kind} // ref $r) =~ s/^STD/VAST/;
185        gen_class($class);
186        $match->{''} = bless $r, $class;
187    }
188
189    sub gen_class {
190        my $class = shift;
191        no strict 'refs';
192        return if @{$class . '::ISA'};
193        warn "Creating class $class\n" if $OPT_log;
194        @{$class . '::ISA'} = 'VAST::Base';
195    }
196
197}
198
199###################################################################
200
201{ package VAST::Base;
202    sub emit_p5 { die "Perl 5 emitter unimplemented" }
203
204    sub emit_p6 { my $self = shift;
205        my $text = $self->get_ws;
206        my @sym;
207        if (exists $self->{sym}) {
208            my $sym = $self->{sym};
209            if (ref $sym eq 'ARRAY') {
210                @sym = @$sym;
211            }
212            else {
213                @sym = $sym;
214            }
215        }
216        if ($self->{zygs}) {
217            my @zyg = $self->get_zygs;
218            my $arity = $self->{ARITY} // '';
219            my $sym = $self->{sym} // '';
220            if ($arity eq 'BINARY') {
221                $text .= $zyg[0] . $zyg[2] . $zyg[1];
222            }
223            elsif ($arity eq 'UNARY') {
224                if ($self->{arg}{_from} > $self->{_from}) {
225                    $text .= $zyg[0] . $zyg[1];
226                }
227                else {
228                    $text .= $zyg[1] . $zyg[0];
229                }
230            }
231            elsif ($sym eq 'identifier') {
232                $text .= join('', reverse @zyg);
233            }
234            else {
235                $text .= join('', @zyg);
236            }
237        }
238        elsif (exists $self->{TEXT}) {
239            $text .= $self->{TEXT};
240        }
241        elsif (@sym) {
242            $text .= join('', @sym);
243        }
244        $self->ret($text);
245    }
246
247    sub ret { my $self = shift;
248        warn ref $self, " returns ", $_[0], "\n" if $OPT_log;
249        $_[0];
250    }
251
252    sub get_zygs { my $self = shift;
253        my @zygs;
254        if ($self->{zygs}) {
255            my $zygs = $self->{zygs};
256            for my $key (sort {$zygs->{$a} <=> $zygs->{$b}} keys %$zygs) {
257                push @zygs, $self->get_zyg($key);
258            }
259        }
260        @zygs;
261    }
262
263    sub get_zyg { my $self = shift;
264        my $key = shift;
265        my $part = $self->{$key};
266        my @zygs;
267        if (ref $part eq 'ARRAY') {
268            my @kids = @$part;
269            for my $kid (@kids) {
270                if (ref $kid) {
271                    push @zygs, $kid->emit_p6 // '';
272                }
273                else {
274                    push @zygs, $kid;
275                }
276            }
277        }
278        elsif (ref $part) {
279            push @zygs, $part->emit_p6 // '';
280        }
281        else {
282            push @zygs, $key . '=' . $part;
283        }
284        @zygs;
285    }
286
287    sub get_ws { my $self = shift;
288        my $ws = $self->{WS} // 0;
289        my $pos = $self->{POS};
290        if ($ws and not $did_ws[$pos]++) {
291            substr($::ORIG, $pos - $ws, $ws)
292        }
293        else {
294            '';
295        }
296    }
297       
298}
299
300{ package VAST::sample; our @ISA = 'VAST::Base';
301    sub emit_p6 { my $self = shift;
302    }
303}
304
305{ package VAST::PreSym; our @ISA = 'VAST::Base';
306    sub emit_p6 { my $self = shift;
307        my $text = $self->get_ws;
308        $text .= $self->{sym};
309        $text .= $self->SUPER::emit_p6(@_);
310        $text;
311    }
312}
313
314{ package VAST::CircumSym; our @ISA = 'VAST::Base';
315    sub emit_p6 { my $self = shift;
316        my $text = $self->get_ws;
317        $text .= $self->{sym}[0];
318        $text .= $self->SUPER::emit_p6(@_);
319        $text .= $self->{sym}[1];
320        $text;
321    }
322}
323
324{ package VAST::FirstLast; our @ISA = 'VAST::Base';
325    sub emit_p6 { my $self = shift;
326        my $text = $self->get_ws;
327        $text .= $self->{FIRST};
328        $text .= $self->SUPER::emit_p6(@_);
329        $text .= $self->{LAST};
330        $text;
331    }
332}
333
334{ package VAST::comp_unit; our @ISA = 'VAST::Base';
335    sub emit_p6 { my $self = shift;
336        my $text = $self->SUPER::emit_p6(@_);
337        if (not @did_ws[@::MEMOS-1]) {
338            my $finalws = $::MEMOS[-1]{ws};
339            $text .= substr($::ORIG, $finalws, -1) if $finalws;
340        }
341        $self->ret($text);
342    }
343}
344
345{ package VAST::Comma; our @ISA = 'VAST::Base';
346    sub emit_p6 { my $self = shift;
347        my $text = $self->get_ws;
348       
349        my @list = $self->get_zyg('list');
350        my @delims = $self->get_zyg('delims');
351        while (@list) {
352            $text .= shift(@list) . (shift(@delims)//'');
353        }
354        $self->ret($text);
355    }
356}
357
358{ package VAST::statementlist; our @ISA = 'VAST::Base';
359    sub emit_p6 { my $self = shift;
360        my $text = $self->get_ws;
361       
362        my @statement = $self->get_zyg('statement');
363        my @terminator = $self->get_zyg('eat_terminator');
364        while (@statement or @terminator) {
365            $text .= shift(@statement) . (shift(@terminator)//'');
366        }
367        $self->ret($text);
368    }
369}
370
371{ package VAST::nibbler; our @ISA = 'VAST::Base';
372    sub emit_p6 { my $self = shift;
373        my $text = '';
374        my @nibbles = $self->get_zyg('nibbles');
375        for my $nibble (@nibbles) {
376            if (ref $nibble) {
377                $text .= $nibble->emit_p6;
378            }
379            else {
380                $text .= $nibble;
381            }
382        }
383        $self->ret($text);
384    }
385}
386
387{ package VAST::quibble; our @ISA = 'VAST::Base';
388    sub emit_p6 { my $self = shift;
389        my $text = $self->get_ws;
390       
391        my @babble = @{$self->{babble}{B}};
392        my @nibble = $self->get_zyg('nibble');
393        $text .= $babble[0] . $nibble[0] . $babble[1];
394        $self->ret($text);
395    }
396}
397
398{ package VAST::quote; our @ISA = 'VAST::Base';
399    sub emit_p6 { my $self = shift;
400        my $text = $self->get_ws;
401       
402        if ($self->{nibble}) {
403            my @nibble = $self->get_zyg('nibble');
404            $text .= $self->{sym}[0] . $nibble[0] . $self->{sym}[1];
405        }
406        else { 
407            my @quibble = $self->get_zyg('quibble');
408            $text .= $self->{sym} . $quibble[0];
409        }
410        $self->ret($text);
411    }
412}
413
414{ package VAST::variable_declarator; our @ISA = 'VAST::Base';
415    sub emit_p6 { my $self = shift;
416        my $text = $self->get_ws;
417        $text .= ($self->get_zyg('variable'))[0];
418        $text .= join '', $self->get_zyg('shape');
419        $text .= join '', $self->get_zyg('trait');
420        $text .= join '', $self->get_zyg('post_constraint');
421        $text;
422    }
423}
424
425{ package VAST::scope_declarator; our @ISA = 'VAST::PreSym'; }
426{ package VAST::statement_control; our @ISA = 'VAST::PreSym'; }
427{ package VAST::statement_prefix; our @ISA = 'VAST::PreSym'; }
428{ package VAST::version; our @ISA = 'VAST::PreSym'; }
429
430{ package VAST::block; our @ISA = 'VAST::CircumSym'; }
431{ package VAST::circumfix; our @ISA = 'VAST::CircumSym'; }
432{ package VAST::postcircumfix; our @ISA = 'VAST::CircumSym'; }
433{ package VAST::args; our @ISA = 'VAST::FirstLast'; }
434
435if ($0 eq __FILE__) {
436    ::MAIN(@ARGV);
437}
438
439# vim: ts=8 sw=4 noexpandtab smarttab
Note: See TracBrowser for help on using the browser.