From f8e4a320c9a4da9c1818800f3e66d40cae44165f Mon Sep 17 00:00:00 2001 From: jnthn Date: Sat, 16 Feb 2013 12:57:15 +0100 Subject: [PATCH] Initial port of alt. Doesn't actually work yet, since NFA execution is NYI. Howver, the generated code does enough to get us to the point of hitting that. --- lib/QAST/JASTCompiler.nqp | 65 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/lib/QAST/JASTCompiler.nqp b/lib/QAST/JASTCompiler.nqp index 9387821..c5b63e5 100644 --- a/lib/QAST/JASTCompiler.nqp +++ b/lib/QAST/JASTCompiler.nqp @@ -2968,7 +2968,7 @@ class QAST::CompilerJAST { # build the list of (unique) locals we need my %*REG; my $prefix := self.unique('rx') ~ '_'; - my $reglist := nqp::split(' ', 'start o tgt s pos i off i eos i rep i cur o curclass o bstack o cstack o restart i itemp i'); + my $reglist := nqp::split(' ', 'start o tgt s pos i off i eos i rep i cur o curclass o bstack o cstack o restart i itemp i altmarks o'); while $reglist { my $reg := nqp::shift($reglist); my $tc := nqp::shift($reglist); @@ -3045,6 +3045,11 @@ class QAST::CompilerJAST { QAST::Var.new( :name(%*REG), :scope('local') ), QAST::IVal.new( :value(4) ) )), + QAST::Op.new( + :op('bind'), + QAST::Var.new( :name(%*REG), :scope('local') ), + QAST::Op.new( :op('create'), QAST::Op.new( :op('bootintarray') ) ) + ), QAST::Op.new( :op('bind'), QAST::Var.new( :name(%*REG), :scope('local'), :returns(int) ), @@ -3196,6 +3201,64 @@ class QAST::CompilerJAST { self."$rxtype"($node); } + method alt($node) { + unless $node.name { + return self.altseq($node); + } + + # Calculate all the branches to try, which populates the bstack + # with the options. Then immediately fail to start iterating it. + my $il := JAST::InstructionList.new(); + my $prefix := self.unique('alt') ~ '_'; + my $endlabel := JAST::Label.new( :name($prefix ~ 'end') ); + + $il.append(JAST::Instruction.new( :op('aload'), %*REG )); + $il.append(JAST::Instruction.new( :op('aload_1') )); + $il.append(JAST::PushIVal.new( :value(0) )); + $il.append(JAST::Instruction.new( :op('invokevirtual'), $TYPE_SMO, + "set_elems", 'Void', $TYPE_TC, 'Long' )); + my $il_marks := JAST::InstructionList.new(); + $il.append($il_marks); + my $mark_endlabel := &*REGISTER_MARK($endlabel); + self.regex_mark($il, $mark_endlabel, + JAST::PushIVal.new( :value(-1) ), + JAST::PushIVal.new( :value(0) )); + + my $altmeth := QAST::Op.new( + :op('callmethod'), :name('!alt'), + QAST::Var.new( :name(%*REG), :scope('local') ), + QAST::Var.new( :name(%*REG), :scope('local'), :returns(int) ), + QAST::SVal.new( :value($node.name) ), + QAST::Var.new( :name(%*REG), :scope('local') ) + ); + $il.append(self.as_jast($altmeth, :want($RT_VOID)).jast); + $il.append(JAST::Instruction.new( :op('goto'), %*REG )); + + # Emit all the possible alternations. + my $altcount := 0; + my $iter := nqp::iterator($node.list); + while $iter { + my $altlabel := JAST::Label.new( :name($prefix ~ $altcount) ); + my $ajast := self.regex_jast(nqp::shift($iter)); + $il.append($altlabel); + $il.append($ajast); + $il.append(JAST::Instruction.new( :op('goto'), $endlabel )); + my $altmark := &*REGISTER_MARK($altlabel); + $il_marks.append(JAST::Instruction.new( :op('aload'), %*REG )); + $il_marks.append(JAST::PushIVal.new( :value($altmark) )); + $il_marks.append(JAST::Instruction.new( :op('aload_1') )); + $il_marks.append(JAST::Instruction.new( :op('invokestatic'), $TYPE_OPS, 'push_i', + 'Long', $TYPE_SMO, 'Long', $TYPE_TC )); + $il_marks.append(JAST::Instruction.new( :op('pop2') )); + $altcount++; + } + + $il.append($endlabel); + self.regex_commit($il, $mark_endlabel) if $node.backtrack eq 'r'; + + $il; + } + method altseq($node) { my $il := JAST::InstructionList.new(); my $prefix := self.unique('alt') ~ '_';