def matchCodeblock( prefix, innerDelimPairs, outerDelimPairs )
startPos = self.pointer
debugMsg 2, "Starting matchCodeblock at offset %d (%s)", startPos, self.rest.inspect
raise MatchFailure, "Did not find prefix: /#{prefix.inspect}/" unless
self.skip( prefix )
codePos = self.pointer
debugMsg 3, "Skipped prefix '%s' to offset %d" %
[ self.matched, codePos ]
ldelimOuter = "(" + outerDelimPairs.keys .uniq.collect {|delim| Regexp::quote(delim)}.join('|') + ")"
rdelimOuter = "(" + outerDelimPairs.values.uniq.collect {|delim| Regexp::quote(delim)}.join('|') + ")"
debugMsg 4, "Using /%s/ as the outer delim regex" % ldelimOuter
unless self.scan( ldelimOuter )
raise MatchFailure, %q:Did not find opening bracket at "%s..." offset %d: %
[ self.rest[0,20].chomp, codePos ]
end
closingDelim = outerDelimPairs[self.matched] or
raise DelimiterError, "Could not find closing delimiter for '%s'" %
self.matched
debugMsg 3, "Scanning for closing delim '#{closingDelim}'"
matched = ''
patvalid = true
while self.rest?
debugMsg 5, "Scanning from offset %d (%s)", self.pointer, self.rest.inspect
matched = ''
debugMsg 5, "Trying to match a comment"
if self.scan( /\s*#.*/ )
debugMsg 4, "Skipping comment '%s' to offset %d" %
[ self.matched, self.pointer ]
next
end
debugMsg 5, "Trying to match a closing outer delimiter with /\s*(#{rdelimOuter})/"
if self.scan( /\s*(#{rdelimOuter})/ )
debugMsg 4, "Found a right delimiter '#{self.matched}'"
if self.matched.strip == closingDelim
matched = self.matched
debugMsg 3, "Found the closing delimiter we've been looking for (#{matched.inspect})."
break
else
raise MatchFailure,
%q:Mismatched closing bracket at "%s..." (offset %s). Expected '%s': %
[ self.rest[0,20], self.pointer, closingDelim ]
end
end
debugMsg 5, "Trying to match either a variable or quotelike"
if self.scanVariable( '\s*' ) || self.scanQuotelike( '\s*', patvalid )
debugMsg 3, "Matched either a variable or quotelike. Offset now %d" % self.pointer
patvalid = false
next
end
debugMsg 5, "Trying to match an operator"
if self.scan( %r:\s*([-+*x/%^&|.]=?
| [!=]~
| =(?!>)
| (\*\*|&&|\|\||<<|>>)=?
| split|grep|map|return
):x )
debugMsg 3, "Skipped miscellaneous operator '%s' to offset %d." %
[ self.matched, self.pointer ]
patvalid = true
next
end
debugMsg 5, "Trying to match an embedded codeblock with delim pairs: %s",
innerDelimPairs.inspect
if self.scanCodeblock( innerDelimPairs )
debugMsg 3, "Skipped inner codeblock to offset %d." % self.pointer
patvalid = true
next
end
debugMsg 5, "Trying to match a stray outer-left delimiter (#{ldelimOuter})"
if self.match?( ldelimOuter )
raise MatchFailure, "Improperly nested codeblock at offset %d: %s... " %
[ self.pointer, self.rest[0,20] ]
end
patvalid = false
self.scan( /\s*(\w+|[-=>]>|.|\Z)/m )
debugMsg 3, "Skipped '%s' to offset %d" %
[ self.matched, self.pointer ]
end
unless matched
raise MatchFailure, "No match found for opening bracket"
end
rval = {
:match => self.string[codePos .. (self.pointer - 1)],
:prefix => self.string[startPos, (codePos-startPos)],
:suffix => self.string[ self.pointer..-1 ],
}
debugMsg 1, "matchCodeblock succeeded: %s" % rval.inspect
return rval
end