expand_args(@args)

Given an argument list, returns a list of all the possible argument combinations.

return list() unless @args;

my $arg := @args.shift;

my @var := list($arg<type>);
if $arg<variant> {
    @var.push($arg<variant>);
}

my @list := expand_args(@args);
unless +@list {
    return @var;
}

my @results;
for @list -> $l {
    for @var -> $v {
        # NQP can't handle it automagically. So wrap $l into list.
        my @l := pir::does__IPS($l, 'array') ?? $l !! list($l);
        @results.push(list($v, |@l));
    }
}

@results;
}

method signature($/) { my $past := PAST::Stmts.new( :node($/) );

for $<op_param> {
    $past.push($_.ast);
}

make $past;
}

method op_param($/) { my $past := PAST::Var.new( :node($/), :isdecl(1) );

# We have to store 2 "types". Just set 2 properties on Var for now
$past<direction> := ~$<op_param_direction>;
$past<type>      := ~$<op_param_type>;

make $past;
}

method op_body($/) { make $<blockoid>.ast; }

method op_macro:sym<expr offset>($/) { make PAST::Op.new( :pasttype<macro>, :name<expr_offset>, $<arg>.ast, ); }

method op_macro:sym<goto offset>($/) { $OP.add_jump('PARROT_JUMP_RELATIVE');

my $past := PAST::Op.new(
    :pasttype<macro>,
    :name<goto_offset>,
    $<arg>.ast,
);

if $OP.need_write_barrier {
    $past := PAST::Block.new(
        self.make_write_barrier,
        $past,
    );
}

make $past;
}

method op_macro:sym<expr address>($/) { make PAST::Op.new( :pasttype<macro>, :name<expr_address>, $<arg>.ast, ); }

method op_macro:sym<goto address>($/) { my $past := PAST::Op.new( :pasttype<macro>, :name<goto_address>, $<arg>.ast, );

if $OP.need_write_barrier {
    $past := PAST::Block.new(
        self.make_write_barrier,
        $past,
    );
}

make $past;
}

method op_macro:sym<expr next>($/) { make PAST::Op.new( :pasttype<macro>, :name<expr_offset>, self.opsize, ); }

method op_macro:sym<goto next>($/) { $OP.add_jump('PARROT_JUMP_RELATIVE');

my $past := PAST::Op.new(
    :pasttype<macro>,
    :name<goto_offset>,
    self.opsize,
);

if $OP.need_write_barrier {
    $past := PAST::Block.new(
        self.make_write_barrier,
        $past,
    );
}

make $past;
}

method op_macro:sym<restart next> ($/) { #say('# op_macro'); # restart NEXT() -> restart_offset(opsize()); goto_address(0) my $past := PAST::Stmts.new( PAST::Op.new( :pasttype<macro>, :name<restart_offset>, self.opsize, ), PAST::Op.new( :pasttype<macro>, :name<goto_address>, PAST::Val.new( :value<0> ) ), );

$past.unshift(self.make_write_barrier) if $OP.need_write_barrier;

make $past;
}

method blockoid ($/) { my $past := PAST::Block.new(:node($/));

$past.push($_) for @($<mixed_content>.ast);

make $past;
}

method mixed_content ($/) { my $past := PAST::Stmts.new(:node($/));

@($_.ast).map(-> $_ { $past.push($_) }) for $<declarator>;
$past.push($_) for @($<statement_list>.ast);

make $past;
}

method declarator ($/) { my $past := PAST::Stmts.new(:node($/)); for $<declarator_name> { my $decl := PAST::Var.new( :node($_), :isdecl(1), :name(~$_<variable>), :vivibase(~$<type_declarator>), );

    $decl.viviself($_<EXPR>[0].ast) if $_<EXPR>[0];

    $decl<array_size> := ~$_<array_size><VALUE> if $_<array_size>;
    $decl<pointer>    := $_<pointer>.join('');
    $past.push($decl);
}

make $past;
}

method statement_list ($/) { my $past := PAST::Stmts.new(:node($/));

$past.push($_.ast) for $<labeled_statement>;

# Avoid wrapping single blockoid into Stmts.
make (+@($past) == 1) && ($past[0] ~~ PAST::Block)
    ?? $past[0]
    !! $past;
}

method labeled_statement ($/) { # FIXME!!! my $past := $<statement> ?? $<statement>.ast !! PAST::Op.new();

# FIXME!!! We need some semantics here.
$past<label> := ~$<label> if $<label>;

make $past;
}

method statement ($/) { my $past;

if $<statement_control> {
    $past := $<statement_control>.ast;
}
elsif $<blockoid> {
    $past := $<blockoid>.ast;
}
elsif $<EXPR> {
    $past := $<EXPR>.ast;
}
elsif $<c_macro> {
    $past := $<c_macro>.ast;
}
else {
    $/.CURSOR.panic("Unknown content in statement");
}

make $past;
}

method c_macro:sym<define> ($/) { my $past := PAST::Op.new( :pasttype<macro_define>, $<name>, );

$past<macro_args> := $<c_macro_args>[0].ast if $<c_macro_args>;
$past<body>       := $<body>[0].ast         if $<body>;

make $past;
}

method c_macro:sym<if> ($/) { my $past := PAST::Op.new( :pasttype<macro_if>,

    ~$<condition>,  # FIXME! We have to parse condition somehow.
    $<then>.ast,
);

$past.push($<else>[0].ast) if $<else>;

make $past;
}

method c_macro:sym<ifdef> ($/) { my $past := PAST::Op.new( :pasttype<macro_if>,

    'defined(' ~ ~$<name> ~ ')',  # FIXME! We have to parse condition somehow.
    $<then>.ast,
);

$past.push($<else>[0].ast) if $<else>;

make $past;
}

method term:sym<concatenate_strings> ($/) { make ~$<identifier> ~ ' ' ~ ~$<quote>; }

method term:sym<identifier> ($/) { # XXX Type vs Variable make PAST::Var.new( :name(~$/), ); }

method term:sym<call> ($/) { my $past := PAST::Op.new( :pasttype('call'), :name(~$<identifier>), );

if ($<arglist><arg>) {
    $past.push($_.ast) for $<arglist><arg>;
}

make $past;
}

method arg ($/) { make $<type_declarator> ?? ~$<type_declarator> !! $<EXPR>.ast; }

method term:sym<reg> ($/) { make PAST::Var.new( :name(+$<num>), :node($/), :scope('register'), # Special scope ); }

method term:sym<macro> ($/) { make $<op_macro>.ast; }

method term:sym<int> ($/) { # TODO Handle type make PAST::Val.new( :value(~$/), :returns<int> ); }

method term:sym<str> ($/) { make PAST::Val.new( :value(~$<quote>), :returns<string> ); }

method term:sym<float_constant_long> ($/) { # longer to work-around lack of LTM make PAST::Val.new( :value(~$/[0]), :returns<float> ); }

method infix:sym<?:> ($/) { my $past := PAST::Op.new( :pasttype<if>, ); # Override to emit ternary ops in .to_c $past<ternary> := 1; make $past; }

method statement_control:sym<if> ($/) { my $past := PAST::Op.new( :pasttype<if>,

    $<EXPR>.ast,
    $<then>.ast,
);

$past.push($<else>[0].ast) if $<else>;

make $past;
}

method statement_control:sym<while> ($/) { my $past := PAST::Op.new( :pasttype<while>,

    $<condition>.ast,
    $<statement_list>.ast,
);

make $past;
}

method statement_control:sym<do-while> ($/) { my $past := PAST::Op.new( :pasttype<do-while>,

    $<blockoid>.ast,
    $<condition>.ast,
);

make $past;
}

method statement_control:sym<for> ($/) { my $past := PAST::Op.new( :pasttype<for>,

    $<init> ?? $<init>[0].ast !! undef,
    $<test> ?? $<test>[0].ast !! undef,
    $<step> ?? $<step>[0].ast !! undef,
    $<statement_list>.ast,
);

make $past;
}

# Not real "C" switch. Just close enough method statement_control:sym<switch> ($/) { my $past := PAST::Op.new( :pasttype<switch>, $<test>.ast, $<statement_list>.ast, ); make $past; }

method statement_control:sym<break> ($/) { my $past := PAST::Op.new(); $past<control> := 'break'; make $past; }

method statement_control:sym<continue> ($/) { my $past := PAST::Op.new(); $past<control> := 'continue'; make $past; }

method statement_or_block ($/) { $<labeled_statement> ?? make PAST::Block.new( $<labeled_statement>.ast ) !! make $<blockoid>.ast }

method circumfix:sym<( )> ($/) { my $past := $<EXPR>.ast;

# Indicate that we need wrapping.
$past<wrap> := 1;

make $past;
}

method postcircumfix:sym<[ ]> ($/) { make PAST::Var.new( $<EXPR>.ast, :scope('keyed'), ); }

# For casting we just set "returns" of EXPR. method prefix:sym<( )> ($/) { make PAST::Op.new( :returns(~$<type_declarator>), ); }

# Helper method for generating PAST::Val with opsize method opsize () { make PAST::Val.new( :value($OP.size), :returns('int'), ); }

method make_write_barrier () { make PAST::Op.new( :pasttype<call>, :name<PARROT_GC_WRITE_BARRIER>, PAST::Var.new( :name<interp> ), PAST::Op.new( :pasttype<call>, :name<CURRENT_CONTEXT>, PAST::Var.new( :name<interp> ) ) ); }

# Local Variables: # mode: perl6 # fill-column: 100 # End: # vim: expandtab ft=perl6 shiftwidth=4:

3 POD Errors

The following errors were encountered while parsing the POD:

Around line 175:

=begin without a target?

Around line 177:

'=item' outside of any '=over'

=over without closing =back

Around line 182:

'=end sub expand_args(@args) {' is invalid. (Stack: =over)