rule code_begin ($type) { <{ { asp => '<%', php => ' '<:' }.{$type} // fail "Unknown type: $type" }> } rule code_end ($type) { <{ { asp => '%>', php => '?>', plp => ':>' }.{$type} // fail "Unknown type: $type" }> } rule code_block ($type) { (.*?) } rule code_document ($type) { [ # First, match any number of subsequent code blocks. [ { $?line := .pos.line } :: { push @?blocks, [ $?line, code => $?code_block ] } ]* # If there is now a code_begin, obviously that is an open block. # (In PLP, that is valid, but let's assume for now that it's not.) [ { $?line := .pos.line } \n* $?context := (\N<,15>) { fail "Unclosed code block on line $?line, near '$?context'" } ]? # And then a piece of text. # (At least one character, to avoid having empty blocks.) [ { $?line := .pos.line } $?html := (.+?) [ > | $ ] :: { push @?blocks, [ $?line, html => $?html ] } ]? ]* } my @parsed = ($asp ~~ //).{blocks}