1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/test/ruby/sentence.rb

339 lines
7.1 KiB
Ruby
Raw Normal View History

# sentence
class Sentence
def initialize(ary)
@sent = ary
end
def to_s
@sent.join('')
end
def to_a
@sent
end
def [](i)
Sentence.new(@sent[i])
end
def inspect
"#<#{self.class}: #{@sent.inspect}>"
end
def subst(target, &b)
Sentence.new(subst_rec(@sent, target, &b))
end
def subst_rec(obj, target, &b)
if obj.respond_to? :to_ary
a = []
obj.each {|e| a << subst_rec(e, target, &b) }
a
elsif target === obj
yield obj
else
obj
end
end
def find_subtree(&b)
if r = find_subtree_rec(@sent, &b)
Sentence.new(r)
else
nil
end
end
def find_subtree_rec(obj, &b)
if obj.respond_to? :to_ary
if b.call obj
return obj
else
obj.each {|e|
r = find_subtree_rec(e, &b)
return r if r
}
end
end
nil
end
def expand(&b)
Sentence.new(expand_rec(@sent, &b))
end
def expand_rec(obj, r=[], &b)
#puts "#{obj.inspect}\t\t#{r.inspect}"
if obj.respond_to? :to_ary
if b.call obj
obj.each {|o|
expand_rec(o, r, &b)
}
else
a = []
obj.each {|o|
expand_rec(o, a, &b)
}
r << a
end
else
r << obj
end
r
end
def Sentence.each(syntax, sym, limit)
Gen.new(syntax).each_tree(sym, limit) {|tree|
yield Sentence.new(tree)
}
end
class Gen
def Gen.each_tree(syntax, sym, limit, &b)
Gen.new(syntax).each_tree(sym, limit, &b)
end
def Gen.each_string(syntax, sym, limit, &b)
Gen.new(syntax).each_string(sym, limit, &b)
end
def initialize(syntax)
@syntax = syntax
end
def self.expand_syntax(syntax)
syntax = remove_underivable_rules(syntax)
syntax = expand_justempty_rules(syntax)
syntax = remove_emptyable_rules(syntax)
syntax = expand_channel_rules(syntax)
syntax = expand_noalt_rules(syntax)
syntax = reorder_rules(syntax)
end
def self.remove_underivable_rules(syntax)
deribable_syms = {}
changed = true
while changed
changed = false
syntax.each {|sym, rules|
next if deribable_syms[sym]
rules.each {|rhs|
if rhs.all? {|e| String === e || deribable_syms[e] }
deribable_syms[sym] = true
changed = true
break
end
}
}
end
result = {}
syntax.each {|sym, rules|
next if !deribable_syms[sym]
rules2 = []
rules.each {|rhs|
rules2 << rhs if rhs.all? {|e| String === e || deribable_syms[e] }
}
result[sym] = rules2.uniq
}
result
end
def self.expand_justempty_rules(syntax)
justempty_syms = {}
changed = true
while changed
changed = false
syntax.each {|sym, rules|
next if justempty_syms[sym]
if rules.all? {|rhs| rhs.all? {|e| justempty_syms[e] } }
justempty_syms[sym] = true
changed = true
end
}
end
result = {}
syntax.each {|sym, rules|
result[sym] = rules.map {|rhs| rhs.reject {|e| justempty_syms[e] } }.uniq
}
result
end
def self.expand_emptyable_syms(rhs, emptyable_syms)
if rhs.empty?
elsif rhs.length == 1
if emptyable_syms[rhs[0]]
yield rhs
yield []
else
yield rhs
end
else
butfirst = rhs[1..-1]
if emptyable_syms[rhs[0]]
expand_emptyable_syms(butfirst, emptyable_syms) {|rhs2|
yield [rhs[0]] + rhs2
yield rhs2
}
else
expand_emptyable_syms(butfirst, emptyable_syms) {|rhs2|
yield [rhs[0]] + rhs2
}
end
end
end
def self.remove_emptyable_rules(syntax)
emptyable_syms = {}
changed = true
while changed
changed = false
syntax.each {|sym, rules|
next if emptyable_syms[sym]
rules.each {|rhs|
if rhs.all? {|e| emptyable_syms[e] }
emptyable_syms[sym] = true
changed = true
break
end
}
}
end
result = {}
syntax.each {|sym, rules|
rules2 = []
rules.each {|rhs|
expand_emptyable_syms(rhs, emptyable_syms) {|rhs2|
rules2 << rhs2
}
}
result[sym] = rules2.uniq
}
result
end
def self.expand_channel_rules(syntax)
channel_rules = {}
syntax.each {|sym, rules|
channel_rules[sym] = {sym=>true}
rules.each {|rhs|
if rhs.length == 1 && Symbol === rhs[0]
channel_rules[sym][rhs[0]] = true
end
}
}
changed = true
while changed
changed = false
channel_rules.each {|sym, set|
n1 = set.size
set.keys.each {|s|
set.update(channel_rules[s])
}
n2 = set.size
changed = true if n1 < n2
}
end
result = {}
syntax.each {|sym, rules|
rules2 = []
channel_rules[sym].each_key {|s|
syntax[s].each {|rhs|
unless rhs.length == 1 && Symbol === rhs[0]
rules2 << rhs
end
}
}
result[sym] = rules2.uniq
}
result
end
def self.expand_noalt_rules(syntax)
noalt_syms = {}
syntax.each {|sym, rules|
if rules.length == 1
noalt_syms[sym] = true
end
}
result = {}
syntax.each {|sym, rules|
rules2 = []
rules.each {|rhs|
rhs2 = []
rhs.each {|e|
if noalt_syms[e]
rhs2.concat syntax[e][0]
else
rhs2 << e
end
}
rules2 << rhs2
}
result[sym] = rules2.uniq
}
result
end
def self.reorder_rules(syntax)
result = {}
syntax.each {|sym, rules|
result[sym] = rules.sort_by {|rhs|
[rhs.find_all {|e| Symbol === e }.length, rhs.length]
}
}
result
end
def each_tree(sym, limit)
generate_from_sym(sym, limit) {|_, tree|
yield tree
}
nil
end
def each_string(sym, limit)
generate_from_sym(sym, limit) {|_, tree|
yield [tree].join('')
}
nil
end
def generate_from_sym(sym, limit, &b)
return if limit < 0
if String === sym
yield limit, sym
else
rules = @syntax[sym]
raise "undefined rule: #{sym}" if !rules
rules.each {|rhs|
if rhs.length == 1 || rules.length == 1
limit1 = limit
else
limit1 = limit-1
end
generate_from_rhs(rhs, limit1, &b)
}
end
nil
end
def generate_from_rhs(rhs, limit)
return if limit < 0
if rhs.empty?
yield limit, []
else
generate_from_sym(rhs[0], limit) {|limit1, child|
generate_from_rhs(rhs[1..-1], limit1) {|limit2, arr|
yield limit2, [child, *arr]
}
}
end
nil
end
end
end