Permalink
Browse files

[QAST::Operations] implement repeat_while/repeat_until

  • Loading branch information...
masak committed May 24, 2012
1 parent a5d179c commit a6c9a36d597f821ccd292697546abdd65932ac6b
Showing with 103 additions and 0 deletions.
  1. +45 −0 src/QAST/Operations.nqp
  2. +58 −0 t/qast/qast.t
View
@@ -268,6 +268,51 @@ for <while until> -> $op_name {
});
}
+for <repeat_while repeat_until> -> $op_name {
+ QAST::Operations.add_core_op($op_name, -> $qastcomp, $op {
+ # Check operand count.
+ my $operands := +$op.list;
+ pir::die("Operation '$op_name' needs 2 operands")
+ if $operands != 2;
+
+ # Create labels.
+ my $while_id := $qastcomp.unique($op_name);
+ my $loop_lbl := $qastcomp.post_new('Label', :result($while_id ~ '_loop'));
+
+ # Compile each of the children; we'll need to look at the result
+ # types and pick an overall result type if in non-void context.
+ my @comp_ops;
+ for $op.list {
+ my $comp := $qastcomp.as_post($_);
+ @comp_ops.push($comp);
+ }
+ my $res_type := 'i';
+ my $res_reg := $*REGALLOC."fresh_$res_type"();
+
+ # Evaluate the condition; store result if needed.
+ my $ops := $qastcomp.post_new('Ops');
+
+ # Emit loop label.
+ $ops.push($loop_lbl);
+ $ops.result($res_reg);
+
+ my $coerced := $qastcomp.coerce(@comp_ops[0], $res_type);
+ $ops.push($coerced);
+ $ops.push_pirop('set', $res_reg, $coerced.result);
+
+ # Emit the loop body; stash the result.
+ my $body := $qastcomp.coerce(@comp_ops[1], $res_type);
+ $ops.push($body);
+ $ops.push_pirop('set', $res_reg, $body.result);
+
+ # Emit the conditional iteration jump.
+ $ops.push_pirop(($op_name eq 'repeat_while' ?? 'if ' !! 'unless ') ~
+ @comp_ops[0].result ~ ' goto ' ~ $loop_lbl.result);
+
+ $ops;
+ });
+}
+
# Binding
QAST::Operations.add_core_op('bind', -> $qastcomp, $op {
# Sanity checks.
View
@@ -667,3 +667,61 @@ is_qast(
),
2,
'until loop works');
+
+is_qast(
+ QAST::Block.new(
+ QAST::Op.new(
+ :op('bind'),
+ QAST::Var.new( :name('$i'), :scope('lexical'), :decl('var'), :returns(int) ),
+ QAST::IVal.new( :value(5) )
+ ),
+ QAST::Op.new(
+ :op('repeat_while'),
+ QAST::Op.new(
+ :op('islt_i'),
+ QAST::Var.new( :name('$i'), :scope('lexical') ),
+ QAST::IVal.new( :value(3) )
+ ),
+ QAST::Op.new(
+ :op('bind'),
+ QAST::Var.new( :name('$i'), :scope('lexical') ),
+ QAST::Op.new(
+ :op('sub_i'),
+ QAST::Var.new( :name('$i'), :scope('lexical') ),
+ QAST::IVal.new( :value(1) )
+ )
+ ),
+ ),
+ QAST::Var.new( :name('$i'), :scope('lexical') ),
+ ),
+ 4,
+ 'repeat_while loop works');
+
+is_qast(
+ QAST::Block.new(
+ QAST::Op.new(
+ :op('bind'),
+ QAST::Var.new( :name('$i'), :scope('lexical'), :decl('var'), :returns(int) ),
+ QAST::IVal.new( :value(0) )
+ ),
+ QAST::Op.new(
+ :op('repeat_until'),
+ QAST::Op.new(
+ :op('islt_i'),
+ QAST::Var.new( :name('$i'), :scope('lexical') ),
+ QAST::IVal.new( :value(3) )
+ ),
+ QAST::Op.new(
+ :op('bind'),
+ QAST::Var.new( :name('$i'), :scope('lexical') ),
+ QAST::Op.new(
+ :op('add_i'),
+ QAST::Var.new( :name('$i'), :scope('lexical') ),
+ QAST::IVal.new( :value(1) )
+ )
+ ),
+ ),
+ QAST::Var.new( :name('$i'), :scope('lexical') ),
+ ),
+ 1,
+ 'repeat_until loop works');

0 comments on commit a6c9a36

Please sign in to comment.