More than once in writing my parsers I hit the issue of finding it easiest to generate an array of hashes, such as:
rule(:var_expr) {
init = str('=') >> space >> expression
var = ident.as(:var_name) >> space >> init.maybe.as(:var_init)
list = str(',') >> space >> var
str('var') >> space >> (var >> list.repeat(0)).as(:var_list) >> space >>
str('in') >> space >> expression.as(:var_expr)
}
Notice var_list will consist of an Array of Hash's in the parse tree. This means var_list can't be matched by the 'sequence' matcher. Since I hit this issue more than once I decided extend Parslet with this 'hash_sequence' matcher:
module MyTransformers
class HashSequenceBind < Parslet::Pattern::SubtreeBind
def initialize(symbol, keys, key_binder=nil)
self.symbol = symbol
@keys = keys
@key_binder = key_binder || Parslet::Pattern::SimpleBind.new
end
def can_bind?(subtree)
subtree.kind_of?(Array) and
subtree.all? { |el|
el.is_a?(Hash) and
el.keys == @keys and
el.all? { |k, v|
@key_binder.can_bind? v
}
}
end
end
end
module Parslet
def hash_sequence(symbol, keys)
MyTransformers::HashSequenceBind.new(symbol, keys)
end
module_function :hash_sequence
end
Notice var_list will match only an Array whose elements are all Hash's with the keys :var_name, and :var_init, and then only if all those values are matched by Parslet::Pattern::SimpleBind. This last behavior is modifiable by the optional third parameter to hash_sequence.
I've used this feature more than once and will make a patch and pull request if others find it useful.
More than once in writing my parsers I hit the issue of finding it easiest to generate an array of hashes, such as:
Notice var_list will consist of an Array of Hash's in the parse tree. This means var_list can't be matched by the 'sequence' matcher. Since I hit this issue more than once I decided extend Parslet with this 'hash_sequence' matcher:
Used in a transform like:
Notice var_list will match only an Array whose elements are all Hash's with the keys :var_name, and :var_init, and then only if all those values are matched by Parslet::Pattern::SimpleBind. This last behavior is modifiable by the optional third parameter to hash_sequence.
I've used this feature more than once and will make a patch and pull request if others find it useful.