~ubuntu-branches/ubuntu/vivid/nqp/vivid-proposed

« back to all changes in this revision

Viewing changes to examples/rubyish/rubyish.nqp

  • Committer: Package Import Robot
  • Author(s): Alessandro Ghedini
  • Date: 2013-11-01 12:09:18 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20131101120918-kx51sl0sxl3exsxi
Tags: 2013.10-1
* New upstream release
* Bump versioned (Build-)Depends on parrot
* Update patches
* Install new README.pod
* Fix vcs-field-not-canonical
* Do not install rubyish examples
* Do not Depends on parrot-devel anymore
* Add 07_disable-serialization-tests.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
use NQPHLL;
 
2
 
 
3
# Ruby subset extended from the `rubyish` example, as introduced in the
 
4
# Edument Rakudo and NQP internals course.
 
5
 
 
6
class RubyishClassHOW {
 
7
    has $!name;
 
8
    has %!methods;
 
9
 
 
10
    method new_type(:$name!) {
 
11
        nqp::newtype(self.new(:$name), 'HashAttrStore')
 
12
    }
 
13
 
 
14
    method add_method($obj, $name, $code) {
 
15
        if nqp::existskey(%!methods, $name) {
 
16
            nqp::die("This class already has a method named " ~ $name);
 
17
        }
 
18
        %!methods{$name} := $code;
 
19
    }
 
20
 
 
21
    method find_method($obj, $name) {
 
22
        %!methods{$name} // nqp::null();
 
23
    }
 
24
}
 
25
 
 
26
grammar Rubyish::Grammar is HLL::Grammar {
 
27
 
 
28
    token TOP {
 
29
        :my $*CUR_BLOCK   := QAST::Block.new(QAST::Stmts.new());
 
30
        :my $*TOP_BLOCK   := $*CUR_BLOCK;
 
31
        :my $*CLASS_BLOCK := $*CUR_BLOCK;
 
32
        :my $*IN_TEMPLATE := 0;
 
33
        :my $*LINE_SPAN   := 0;
 
34
        :my %*SYM         := self.sym-init();
 
35
        ^ ~ $ <stmtlist>
 
36
            || <.panic('Syntax error')>
 
37
    }
 
38
 
 
39
    token continuation   { \\ \n }
 
40
    rule separator       { ';' | \n <!after continuation> }
 
41
    token template-chunk { [<tmpl-unesc>|<tmpl-hdr>] ~ [<tmpl-esc>|$] <template-nibble>* }
 
42
    proto token template-nibble {*}
 
43
    token template-nibble:sym<interp>     { <interp> }
 
44
    token template-nibble:sym<stray-tag>  { [<.tmpl-unesc>|<.tmpl-hdr>] <.panic("Stray tag, e.g. '%>' or '<?rbi?>'")> }
 
45
    token template-nibble:sym<plain-text> { [<!before [<tmpl-esc>|'#{'|$]> .]+ }
 
46
 
 
47
    token tmpl-hdr   {'<?rbi?>' \h* \n? <?{$*IN_TEMPLATE := 1}>}
 
48
    token tmpl-esc   {\h* '<%'
 
49
                     [<?{$*IN_TEMPLATE}> || <.panic('Template directive precedes "<?rbi?>"')>]
 
50
    }
 
51
    token tmpl-unesc { '%>' \h* \n?
 
52
                     [<?{$*IN_TEMPLATE}> || <.panic('Template directive precedes "<?rbi?>"')>]
 
53
    }
 
54
 
 
55
    rule stmtlist {
 
56
        [ <stmt=.stmtish>? ] *%% [<.separator>|<stmt=.template-chunk>]
 
57
    }
 
58
 
 
59
    token stmtish {
 
60
        <stmt> [:s <modifier> :s <EXPR>]?
 
61
    }
 
62
 
 
63
    token modifier {if|unless|while|until}
 
64
 
 
65
    proto token stmt {*}
 
66
 
 
67
    token stmt:sym<def> {
 
68
        :my %sym-save := self.hcopy(%*SYM);
 
69
 
 
70
        'def' ~ 'end' <defbody>
 
71
 
 
72
        <?{%*SYM := self.hcopy(%sym-save);1}>
 
73
    }
 
74
 
 
75
    rule defbody {
 
76
        :my $*CUR_BLOCK := QAST::Block.new(QAST::Stmts.new());
 
77
        <operation> ['(' ~ ')' <signature>]? <separator>?
 
78
        <stmtlist>
 
79
    }
 
80
 
 
81
    token comma { :s [','|'=>'] :s }
 
82
 
 
83
    rule signature {
 
84
        :my $*LINE_SPAN := 1; <param>* %% <comma>
 
85
    }
 
86
 
 
87
    token param { <ident> }
 
88
 
 
89
    token stmt:sym<class> {
 
90
        :my $*IN_CLASS := 1;
 
91
        :my @*METHODS;
 
92
        :my %sym-save := self.hcopy(%*SYM);
 
93
 
 
94
        [<sym> \h+] ~ [\h* 'end'] <classbody>
 
95
 
 
96
        <?{%*SYM := self.hcopy(%sym-save);1}>
 
97
    }
 
98
 
 
99
    rule classbody {
 
100
        :my $*CUR_BLOCK   := QAST::Block.new(QAST::Stmts.new());
 
101
        :my $*CLASS_BLOCK := $*CUR_BLOCK;
 
102
        <ident> <separator>
 
103
        <stmtlist>
 
104
    }
 
105
 
 
106
    token stmt:sym<EXPR> { <EXPR> }
 
107
    token term:sym<assign> { <var> \h* <OPER=infix> '=' \h* <EXPR> }
 
108
 
 
109
    token term:sym<call> {
 
110
        <!keyword>
 
111
        <operation> ['(' ~ ')' <call-args=.paren-args>?
 
112
                    | \h* <call-args>? <?{%*SYM{~$<operation>} eq 'def'}> ]
 
113
    }
 
114
 
 
115
    token term:sym<nqp-op> {
 
116
        'nqp:'':'?<ident> ['(' ~ ')' <call-args=.paren-args>? | <call-args>? ]
 
117
    }
 
118
 
 
119
    token term:sym<quote-words> {
 
120
        \% w <?before [.]> <quote_EXPR: ':q', ':w'>
 
121
    }
 
122
 
 
123
    token call-args  { :s <EXPR>+ % <comma> }
 
124
    token paren-args {:my $*LINE_SPAN := 1; <call-args> }
 
125
 
 
126
    token operation {<ident>[\!|\?]?}
 
127
 
 
128
    token term:sym<new> {
 
129
        ['new' \h+ :s <ident> | <ident> '.' 'new'] ['(' ~ ')' <call-args=.paren-args>?]?
 
130
    }
 
131
 
 
132
    token term:sym<lambda-call> {
 
133
        <ident> '.' 'call' ['(' ~ ')' <call-args=.paren-args>?]?
 
134
    }
 
135
 
 
136
    token var {
 
137
        :my $*MAYBE_DECL := 0;
 
138
        [$<sigil>=[\$|\@\@?]|<!keyword>]
 
139
        \+?<ident>
 
140
        [ <?before \h* '=' [\w | \h+ || <EXPR>] { $*MAYBE_DECL := 1 }> || <?> ]
 
141
    }
 
142
 
 
143
    token term:sym<var> { <var> }
 
144
 
 
145
    token term:sym<value> { \+? <value> }
 
146
 
 
147
    proto token value {*}
 
148
    token value:sym<string>  {<strings>}
 
149
    token strings            {<string> [\h*<strings>]?}
 
150
    token string             { <?[']> <quote_EXPR: ':q'>
 
151
                             | <?["]> <quote_EXPR: ':qq'>
 
152
                             | \%[ q <?before [.]> <quote_EXPR: ':q'>
 
153
                                 | Q <?before [.]> <quote_EXPR: ':qq'>
 
154
                                 ]
 
155
                             }
 
156
 
 
157
    token paren-list {
 
158
         :my $*LINE_SPAN := 1;
 
159
         <EXPR> *%% <comma>
 
160
    }
 
161
 
 
162
    token value:sym<integer> { \+? \d+ }
 
163
    token value:sym<float>   { \+? \d* '.' \d+ }
 
164
    token value:sym<array>   {'[' ~ ']' <paren-list> }
 
165
    token value:sym<hash>    {'{' ~ '}' <paren-list> }
 
166
    token value:sym<nil>     { <sym> }
 
167
    token value:sym<true>    { <sym> }
 
168
    token value:sym<false>   { <sym> }
 
169
 
 
170
    # Interpolation
 
171
    token interp      { '#{' ~ '}' [ :s <stmt> :s
 
172
                                  || <panic('string interpolation error')>]
 
173
                       }
 
174
    token quote_escape:sym<#{ }> { <interp>  }
 
175
 
 
176
    # Reserved words.
 
177
    token keyword {
 
178
        [ BEGIN     | class     | ensure    | nil       | new       | when
 
179
        | END       | def       | false     | not       | super     | while
 
180
        | alias     | defined   | for       | or        | then      | yield
 
181
        | and       | do        | if        | redo      | true
 
182
        | begin     | else      | in        | rescue    | undef
 
183
        | break     | elsif     | module    | retry     | unless
 
184
        | case      | end       | next      | return    | until
 
185
        ] <!ww>
 
186
    }
 
187
 
 
188
    proto token comment {*}
 
189
    token comment:sym<line>   { '#' [<?{!$*IN_TEMPLATE}> \N* || [<!before <tmpl-unesc>>\N]*] }
 
190
    token comment:sym<podish> {[^^'=begin'\n] ~ [^^'=end'\n ] .*?}
 
191
    token ws { <!ww> [\h | <.comment> | <.continuation> | <?{$*LINE_SPAN}> \n]* }
 
192
 
 
193
    # Operator precedence levels
 
194
    INIT {
 
195
        Rubyish::Grammar.O(':prec<y=>, :assoc<unary>', '%unary');
 
196
        Rubyish::Grammar.O(':prec<w=>, :assoc<left>',  '%exponentiation');
 
197
        Rubyish::Grammar.O(':prec<u=>, :assoc<left>',  '%multiplicative');
 
198
        Rubyish::Grammar.O(':prec<r=>, :assoc<left>',  '%concatenation');
 
199
        Rubyish::Grammar.O(':prec<t=>, :assoc<left>',  '%additive');
 
200
        Rubyish::Grammar.O(':prec<j=>, :assoc<right>', '%assignment');
 
201
        Rubyish::Grammar.O(':prec<l=>, :assoc<left>',  '%tight_and');
 
202
        Rubyish::Grammar.O(':prec<k=>, :assoc<left>',  '%tight_or');
 
203
        Rubyish::Grammar.O(':prec<d=>, :assoc<left>',  '%loose_and');
 
204
        Rubyish::Grammar.O(':prec<c=>, :assoc<left>',  '%loose_or');
 
205
    }
 
206
 
 
207
    # Operators - mostly stolen from NQP
 
208
    token prefix:sym<-> { <sym>  <O('%unary, :op<neg_n>')> }
 
209
 
 
210
    token infix:sym<**> { <sym>  <O('%exponentiation, :op<pow_n>')> }
 
211
 
 
212
    token infix:sym<~>  { <sym> <O('%concatenation , :op<concat>')> }
 
213
    token infix:sym<*>  { <sym> <O('%multiplicative, :op<mul_n>')> }
 
214
    token infix:sym</>  { <sym> <O('%multiplicative, :op<div_n>')> }
 
215
    token infix:sym<%>  { <sym><![>]> <O('%multiplicative, :op<mod_n>')> }
 
216
 
 
217
    token infix:sym<+>  { <sym> <O('%additive, :op<add_n>')> }
 
218
    token infix:sym<->  { <sym> <O('%additive, :op<sub_n>')> }
 
219
    token infix:sym<=>  { <sym><!before '>'> <O('%assignment, :op<bind>')> }
 
220
 
 
221
    token infix:sym«==»   { <sym>  <O('%relational, :op<iseq_n>')> }
 
222
    token infix:sym«!=»   { <sym>  <O('%relational, :op<isne_n>')> }
 
223
    token infix:sym«<=»   { <sym>  <O('%relational, :op<isle_n>')> }
 
224
    token infix:sym«>=»   { <sym>  <O('%relational, :op<isge_n>')> }
 
225
    token infix:sym«<»    { <sym>  <O('%relational, :op<islt_n>')> }
 
226
    token infix:sym«>»    { <sym>  <O('%relational, :op<isgt_n>')> }
 
227
    token infix:sym«eq»   { <sym>  <O('%relational, :op<iseq_s>')> }
 
228
    token infix:sym«ne»   { <sym>  <O('%relational, :op<isne_s>')> }
 
229
    token infix:sym«le»   { <sym>  <O('%relational, :op<isle_s>')> }
 
230
    token infix:sym«ge»   { <sym>  <O('%relational, :op<isge_s>')> }
 
231
    token infix:sym«lt»   { <sym>  <O('%relational, :op<islt_s>')> }
 
232
    token infix:sym«gt»   { <sym>  <O('%relational, :op<isgt_s>')> }
 
233
 
 
234
    token infix:sym<&&>   { <sym>  <O('%tight_and,  :op<if>')> }
 
235
    token infix:sym<||>   { <sym>  <O('%tight_or,   :op<unless>')> }
 
236
    token infix:sym<//>   { <sym>  <O('%tight_or,   :op<defor>')> }
 
237
 
 
238
    token infix:sym<and>  { <sym>  <O('%loose_and,  :op<if>')> }
 
239
    token infix:sym<or>   { <sym>  <O('%loose_or,   :op<unless>')> }
 
240
 
 
241
    # Parenthesis
 
242
    token circumfix:sym<( )> {'(' <.ws> <EXPR> ')' <O('%methodop')> }
 
243
 
 
244
    # Method call
 
245
    token postfix:sym<.>  {
 
246
        '.' <ident> [ '(' ~ ')' <call-args=.paren-args>? ]?
 
247
        <O('%methodop')>
 
248
    }
 
249
 
 
250
    # Array and hash indices
 
251
    token postcircumfix:sym<[ ]> { '[' ~ ']' [ <EXPR> ] <O('%methodop')> }
 
252
    token postcircumfix:sym<{ }> { '{' ~ '}' [ <EXPR> ] <O('%methodop')> }
 
253
    token postcircumfix:sym<ang> {
 
254
        <?[<]> <quote_EXPR: ':q'>
 
255
        <O('%methodop')>
 
256
    }
 
257
 
 
258
    # Ternarys
 
259
    token infix:sym<? :> {
 
260
        '?'
 
261
        :s
 
262
        <EXPR('i=')>
 
263
        ':'
 
264
        <O('%conditional, :reducecheck<ternary>, :op<if>')>
 
265
    }
 
266
 
 
267
    # Statement control
 
268
    rule xblock {
 
269
        <EXPR> [ <separator> [:s 'then']? | 'then' | <?before <tmpl-unesc>>] <stmtlist>
 
270
    }
 
271
 
 
272
    token stmt:sym<if> {
 
273
        if ~ 'end' [ :s <xblock> [<else=.elsif>|<else>]? ]
 
274
    }
 
275
 
 
276
    token elsif {
 
277
        'elsif' ~ [<else=.elsif>|<else>]? <xblock>
 
278
    }
 
279
 
 
280
    token else {
 
281
         'else' <stmtlist>
 
282
    }
 
283
 
 
284
    token stmt:sym<do> {
 
285
        <modifier> :s <EXPR> :s <do> ~ 'end' <stmtlist>
 
286
    }
 
287
 
 
288
    token stmt:sym<for> {
 
289
        <sym> :s <ident> :s 'in' <EXPR> <do> ~ 'end' <stmtlist>
 
290
    }
 
291
 
 
292
    token do { <separator> [:s 'do']? | 'do' | <?before <tmpl-unesc>>}
 
293
 
 
294
    token term:sym<code>  {
 
295
        'begin' ~ 'end' <stmtlist> 
 
296
    }
 
297
 
 
298
    token term:sym<lambda>  {
 
299
        'lambda' :s ['{' ['|' ~ '|' <signature>]?]  ~ '}' <stmtlist> 
 
300
    }
 
301
 
 
302
    method builtin-init() {
 
303
        nqp::hash(
 
304
            'abort',  'die',
 
305
            'exit',   'exit',
 
306
            'print',  'print',
 
307
            'puts',   'say',
 
308
            'sleep',  'sleep',
 
309
            );
 
310
    }
 
311
 
 
312
    method sym-init() {
 
313
        my %builtins := self.builtin-init();
 
314
        my %sym;
 
315
        %sym{$_} := 'def' for %builtins;
 
316
        return %sym;
 
317
    }
 
318
 
 
319
    method hcopy(%in) {
 
320
        my %out;
 
321
        %out{$_} := %in{$_} for %in;
 
322
        return %out;
 
323
    }
 
324
}
 
325
 
 
326
class Rubyish::Actions is HLL::Actions {
 
327
 
 
328
    method TOP($/) {
 
329
        $*CUR_BLOCK.push($<stmtlist>.ast);
 
330
        make $*CUR_BLOCK;
 
331
    }
 
332
 
 
333
    method stmtlist($/) {
 
334
        my $stmts := QAST::Stmts.new( :node($/) );
 
335
 
 
336
        if $<stmt> {
 
337
            $stmts.push($_.ast)
 
338
                for $<stmt>;
 
339
        }
 
340
 
 
341
        make $stmts;
 
342
    }
 
343
 
 
344
    method template-chunk($/) {
 
345
        my $text := QAST::Stmts.new( :node($/) );
 
346
        $text.push( QAST::Op.new( :op<print>, $_.ast ) )
 
347
            for $<template-nibble>;
 
348
        
 
349
        make $text;
 
350
    }
 
351
 
 
352
    method template-nibble:sym<interp>($/) {
 
353
        make $<interp>.ast
 
354
    }
 
355
 
 
356
    method template-nibble:sym<plain-text>($/) {
 
357
        make QAST::SVal.new( :value(~$/) );
 
358
    }
 
359
 
 
360
    method stmtish($/) {
 
361
        make $<modifier>
 
362
            ?? QAST::Op.new( $<EXPR>.ast, $<stmt>.ast,
 
363
                             :op(~$<modifier>), :node($/) )
 
364
            !! $<stmt>.ast;
 
365
    }
 
366
 
 
367
    method term:sym<value>($/) { make $<value>.ast; }
 
368
 
 
369
    # a few ops that map directly to Ruby built-ins
 
370
    my %builtins;
 
371
 
 
372
    method term:sym<call>($/) {
 
373
        my $name  := ~$<operation>;
 
374
        %builtins := Rubyish::Grammar.builtin-init()
 
375
            unless %builtins<puts>;
 
376
        my $op    := %builtins{$name};
 
377
 
 
378
        my $call := $op
 
379
            ?? QAST::Op.new( :op($op) )
 
380
            !! QAST::Op.new( :op('call'), :name($name) );
 
381
 
 
382
        if $<call-args> {
 
383
            $call.push($_)
 
384
                for $<call-args>.ast;
 
385
        }
 
386
 
 
387
        make $call;
 
388
    }
 
389
 
 
390
    method term:sym<nqp-op>($/) {
 
391
        my $op := ~$<ident>;
 
392
        my $call := QAST::Op.new( :op($op) );
 
393
 
 
394
        if $<call-args> {
 
395
            $call.push($_)
 
396
                for $<call-args>.ast;
 
397
        }
 
398
 
 
399
        make $call;
 
400
    }
 
401
 
 
402
    method call-args($/) {
 
403
        my @args;
 
404
        @args.push($_.ast) for $<EXPR>;
 
405
        make @args;
 
406
    }
 
407
 
 
408
    method paren-args($/) {
 
409
        make $<call-args>.ast;
 
410
    }
 
411
 
 
412
    my $tmpsym := 0;
 
413
 
 
414
    method term:sym<new>($/) {
 
415
 
 
416
        # seems a bit hacky
 
417
        my $tmp-sym := '$new' ~ (++$tmpsym) ~ '$';
 
418
 
 
419
        my $init-call := QAST::Op.new( :op<callmethod>,
 
420
                                       :name<initialize>,
 
421
                                       QAST::Var.new( :name($tmp-sym), :scope<lexical> )
 
422
            );
 
423
 
 
424
        if $<call-args> {
 
425
            $init-call.push($_)
 
426
                for $<call-args>.ast;
 
427
        }
 
428
 
 
429
        make QAST::Stmt.new(
 
430
 
 
431
            # create the new object
 
432
            QAST::Op.new( :op('bind'),
 
433
                          QAST::Var.new( :name($tmp-sym), :scope<lexical>, :decl<var>),
 
434
                          QAST::Op.new(
 
435
                              :op('create'),
 
436
                              QAST::Var.new( :name('::' ~ ~$<ident>), :scope('lexical') )
 
437
                          ),
 
438
            ),
 
439
 
 
440
            # call initialize method, if available
 
441
            QAST::Op.new( :op<if>,
 
442
                          QAST::Op.new( :op<can>,
 
443
                                        QAST::Var.new( :name($tmp-sym), :scope<lexical> ),
 
444
                                        QAST::SVal.new( :value<initialize> )),
 
445
                          $init-call,
 
446
            ),
 
447
 
 
448
            # return the new object
 
449
            QAST::Var.new( :name($tmp-sym), :scope<lexical> ),
 
450
            );
 
451
    }
 
452
 
 
453
    method term:sym<lambda-call>($/) {
 
454
        my $call := QAST::Op.new( :op<call>,
 
455
                                  :name(~$<ident>),
 
456
            );
 
457
        if $<call-args> {
 
458
            $call.push($_)
 
459
                for $<call-args>.ast;
 
460
        }
 
461
        make $call;
 
462
    }
 
463
 
 
464
    method var($/) {
 
465
        my $sigil := ~$<sigil>//'';
 
466
        my $name := $sigil ~ $<ident>;
 
467
        my $block;
 
468
        my $decl := 'var';
 
469
 
 
470
        if $sigil eq '@' && $*IN_CLASS {
 
471
            # instance variable
 
472
            make QAST::Var.new( :scope('attribute'),
 
473
                                QAST::Var.new( :name('self'), :scope('lexical')),
 
474
                                QAST::SVal.new( :value($name) )
 
475
                );
 
476
        }
 
477
        else {
 
478
            if $*MAYBE_DECL {
 
479
 
 
480
                if !$sigil {
 
481
                    $block := $*CUR_BLOCK;
 
482
                }
 
483
                elsif $sigil eq '$' {
 
484
                    $block := $*TOP_BLOCK;
 
485
                }
 
486
                elsif $sigil eq '@' {
 
487
                    $block := $*CLASS_BLOCK;
 
488
                }
 
489
                elsif $sigil eq '@@' {
 
490
                    $block := $*CLASS_BLOCK;
 
491
                    $decl  := 'static';                 
 
492
                }
 
493
                else {
 
494
                    nqp::die("unhandled sigil: $sigil");
 
495
                }
 
496
 
 
497
                my %sym  := $block.symbol($name);
 
498
                if !%sym<declared> {
 
499
                    %*SYM{$name} := 'var';
 
500
                    $block.symbol($name, :declared(1), :scope('lexical') );
 
501
                    my $var := QAST::Var.new( :name($name), :scope('lexical'),
 
502
                                              :decl($decl) );
 
503
                    $block[0].push($var);
 
504
                }
 
505
            }
 
506
 
 
507
            make QAST::Var.new( :name($name), :scope('lexical') );
 
508
        }
 
509
    }
 
510
 
 
511
    method term:sym<var>($/) { make $<var>.ast }
 
512
 
 
513
    method stmt:sym<def>($/) {
 
514
        my $install := $<defbody>.ast;
 
515
        $*CUR_BLOCK[0].push(QAST::Op.new(
 
516
            :op('bind'),
 
517
            QAST::Var.new( :name($install.name), :scope('lexical'), :decl('var') ),
 
518
            $install
 
519
        ));
 
520
        %*SYM{$install.name} := 'def';
 
521
        if $*IN_CLASS {
 
522
            @*METHODS.push($install);
 
523
        }
 
524
        make QAST::Op.new( :op('null') );
 
525
    }
 
526
 
 
527
    method defbody($/) {
 
528
        $*CUR_BLOCK.name(~$<operation>);
 
529
        if $<signature> {
 
530
            for $<signature>.ast {
 
531
                $*CUR_BLOCK[0].push($_);
 
532
                $*CUR_BLOCK.symbol($_.name, :declared(1));
 
533
            }
 
534
        }
 
535
        $*CUR_BLOCK.push($<stmtlist>.ast);
 
536
        if $*IN_CLASS {
 
537
            # it's a method, self will be automatically passed
 
538
            $*CUR_BLOCK[0].unshift(QAST::Var.new(
 
539
                :name('self'), :scope('lexical'), :decl('param')
 
540
            ));
 
541
            $*CUR_BLOCK.symbol('self', :declared(1));
 
542
        }
 
543
 
 
544
        make $*CUR_BLOCK;
 
545
    }
 
546
 
 
547
    method signature($/) {
 
548
        my @params;
 
549
        for $<param> {
 
550
              @params.push(QAST::Var.new(
 
551
                :name(~$_), :scope('lexical'), :decl('param')
 
552
            ));
 
553
        }
 
554
        make @params;
 
555
    }
 
556
 
 
557
    method stmt:sym<class>($/) {
 
558
        my $body_block := $<classbody>.ast;
 
559
 
 
560
        # Generate code to create the class.
 
561
        my $class_stmts := QAST::Stmts.new( $body_block );
 
562
        my $ins_name    := '::' ~ $<classbody><ident>;
 
563
        $class_stmts.push(QAST::Op.new(
 
564
            :op('bind'),
 
565
            QAST::Var.new( :name($ins_name), :scope('lexical'), :decl('var') ),
 
566
            QAST::Op.new(
 
567
                :op('callmethod'), :name('new_type'),
 
568
                QAST::WVal.new( :value(RubyishClassHOW) ),
 
569
                QAST::SVal.new( :value(~$<classbody><ident>), :named('name') ) )
 
570
            ));
 
571
 
 
572
        # Add methods.
 
573
        my $class_var := QAST::Var.new( :name($ins_name), :scope('lexical') );
 
574
 
 
575
        for @*METHODS {
 
576
            $class_stmts.push(QAST::Op.new(
 
577
                :op('callmethod'), :name('add_method'),
 
578
                QAST::Op.new( :op('how'), $class_var ),
 
579
                $class_var,
 
580
                QAST::SVal.new( :value($_.name) ),
 
581
                QAST::BVal.new( :value($_) )));
 
582
        }
 
583
 
 
584
        make $class_stmts;
 
585
    }
 
586
    method classbody($/) {
 
587
        $*CUR_BLOCK.push($<stmtlist>.ast);
 
588
        $*CUR_BLOCK.blocktype('immediate');
 
589
        make $*CUR_BLOCK;
 
590
    }
 
591
 
 
592
    method stmt:sym<EXPR>($/) { make $<EXPR>.ast; }
 
593
 
 
594
    method term:sym<assign>($/) { 
 
595
        my $op := $<OPER><O><op>;
 
596
        make  QAST::Op.new( :op('bind'),
 
597
                            $<var>.ast,
 
598
                            QAST::Op.new( :op($op),
 
599
                                          $<var>.ast,
 
600
                                          $<EXPR>.ast
 
601
                            ));
 
602
    }
 
603
 
 
604
    method value:sym<string>($/) {
 
605
        make $<strings>.ast;
 
606
    }
 
607
 
 
608
    method strings($/) {
 
609
        make $<strings>
 
610
            ?? QAST::Op.new( :op('concat'), $<string>.ast, $<strings>.ast)
 
611
            !! $<string>.ast;
 
612
    }
 
613
 
 
614
    method string($/) {
 
615
        make $<quote_EXPR>.ast;
 
616
    }
 
617
 
 
618
    method value:sym<integer>($/) {
 
619
        make QAST::IVal.new( :value(+$/.Str) )
 
620
    }
 
621
 
 
622
    method value:sym<float>($/) {
 
623
        make QAST::NVal.new( :value(+$/.Str) )
 
624
    }
 
625
 
 
626
    method paren-list($/) {
 
627
        my @list;
 
628
        if $<EXPR> {
 
629
            @list.push($_.ast) for $<EXPR>
 
630
        }
 
631
        make @list;
 
632
    }
 
633
 
 
634
    method value:sym<array>($/) {
 
635
        my $array := QAST::Op.new( :op<list> );
 
636
        $array.push($_) for $<paren-list>.ast;
 
637
        make $array;
 
638
    }
 
639
 
 
640
    method term:sym<quote-words>($/) {
 
641
        make $<quote_EXPR>.ast;
 
642
    }
 
643
 
 
644
    method value:sym<hash>($/) {
 
645
        my $hash := QAST::Op.new( :op<hash> );
 
646
        $hash.push($_) for $<paren-list>.ast;
 
647
        make $hash;
 
648
    }
 
649
 
 
650
    method value:sym<nil>($/) {
 
651
        make QAST::Op.new( :op<null> );
 
652
    }
 
653
 
 
654
    method value:sym<true>($/) {
 
655
        make QAST::IVal.new( :value<1> );
 
656
    }
 
657
 
 
658
    method value:sym<false>($/) {
 
659
        make QAST::IVal.new( :value<0> );
 
660
    }
 
661
 
 
662
    method  interp($/) { make $<stmt>.ast }
 
663
    method  quote_escape:sym<#{ }>($/) { make $<interp>.ast }
 
664
    method circumfix:sym<( )>($/) { make $<EXPR>.ast }
 
665
 
 
666
    method postfix:sym<.>($/) {
 
667
        my $meth_call := QAST::Op.new( :op('callmethod'), :name(~$<ident>) );
 
668
        if $<call-args> {
 
669
            $meth_call.push($_) for $<call-args>.ast;
 
670
        }
 
671
        make $meth_call;
 
672
    }
 
673
 
 
674
    method postcircumfix:sym<[ ]>($/) {
 
675
        make QAST::Var.new( :scope('positional'), $<EXPR>.ast );
 
676
    }
 
677
 
 
678
    method postcircumfix:sym<{ }>($/) {
 
679
        make QAST::Var.new( :scope('associative'), $<EXPR>.ast );
 
680
    }
 
681
 
 
682
    method postcircumfix:sym<ang>($/) {
 
683
        make QAST::Var.new( :scope('associative'), $<quote_EXPR>.ast );
 
684
    }
 
685
 
 
686
    # borrowed from NQP::Actions
 
687
    method xblock($/) {
 
688
        make QAST::Op.new( $<EXPR>.ast, $<stmtlist>.ast, :op('if'), :node($/) );
 
689
    }
 
690
 
 
691
    method stmt:sym<if>($/) {
 
692
        my $ast :=  $<xblock>.ast;
 
693
        $ast.push( $<else>.ast )
 
694
            if $<else>;
 
695
 
 
696
        make $ast;
 
697
    }
 
698
 
 
699
    method elsif($/) {
 
700
        my $ast :=  $<xblock>.ast;
 
701
        $ast.push( $<else>.ast )
 
702
            if $<else>;
 
703
 
 
704
        make $ast;
 
705
    }
 
706
 
 
707
    method else($/) {
 
708
        make $<stmtlist>.ast
 
709
    }
 
710
 
 
711
    method stmt:sym<do>($/) {
 
712
        make QAST::Op.new( $<EXPR>.ast, $<stmtlist>.ast, :op(~$<modifier>), :node($/) );
 
713
    }
 
714
 
 
715
    method stmt:sym<for>($/) {
 
716
 
 
717
        my $block := QAST::Block.new(
 
718
            QAST::Var.new( :name(~$<ident>), :scope('lexical'), :decl('param')),
 
719
            $<stmtlist>.ast);
 
720
 
 
721
        make QAST::Op.new( $<EXPR>.ast, $block, :op('for'), :node($/) );
 
722
    }
 
723
 
 
724
    method term:sym<code>($/) {
 
725
        make $<stmtlist>.ast;
 
726
    }
 
727
 
 
728
    method term:sym<lambda>($/) {
 
729
        my $block := QAST::Block.new();
 
730
        if $<signature> {
 
731
            for $<signature>.ast {
 
732
                $block.push($_);
 
733
                $block.symbol($_.name, :declared(1));
 
734
            }
 
735
        }
 
736
        $block.push($<stmtlist>.ast);
 
737
 
 
738
        make  QAST::Op.new(:op<takeclosure>,
 
739
                           $block,
 
740
            );
 
741
    }
 
742
 
 
743
}
 
744
 
 
745
class Rubyish::Compiler is HLL::Compiler {
 
746
}
 
747
 
 
748
sub MAIN(*@ARGS) {
 
749
    my $comp := Rubyish::Compiler.new();
 
750
    $comp.language('rubyish');
 
751
    $comp.parsegrammar(Rubyish::Grammar);
 
752
    $comp.parseactions(Rubyish::Actions);
 
753
    $comp.command_line(@ARGS, :encoding('utf8'));
 
754
}