class ABNF
Constants
- FIXUP_NAMES
Attributes
ast[RW]
parser[RW]
rules[RW]
tree[RW]
Public Class Methods
from_abnf(s)
click to toggle source
# File lib/abnftt.rb, line 48 def self.from_abnf(s) ast = @@parser.parse s if !ast fail self.reason(@@parser, s) end ABNF.new(ast) end
new(ast_)
click to toggle source
# File lib/abnftt.rb, line 57 def initialize(ast_) @ast = ast_ @tree = ast.ast @rules = {} @tree.each do |x| op, name, val, rest = x fail rest if rest @rules[name] = if old = @rules[name] fail "duplicate rule for name #{name}" if op == "=" if Array === old && old[0] == "alt" old.dup << val else ["alt", old, val] end else val end end # warn "** rules #{rules.inspect}" end
reason(parser, s)
click to toggle source
# File lib/abnftt.rb, line 37 def self.reason(parser, s) reason = [parser.failure_reason] parser.failure_reason =~ /^(Expected .+) after/m reason << "#{$1.gsub("\n", '<<<NEWLINE>>>')}:" if $1 if line = s.lines.to_a[parser.failure_line - 1] reason << line reason << "#{'~' * (parser.failure_column - 1)}^" end reason.join("\n") end
Public Instance Methods
generate()
click to toggle source
# File lib/abnftt.rb, line 79 def generate generate1(rules.first.first) end
generate1(what)
click to toggle source
# File lib/abnftt.rb, line 83 def generate1(what) case what when String expansion = rules[what] fail "can't find rules #{what}" unless expansion generate1(expansion) when Array op, *args = what case op when "seq" args.map {|arg| generate1(arg)}.join when "alt" generate1(args.sample) when "rep" l, h, x, rest = args fail rest if rest h = l+3 if h == true n = rand(h-l+1)+l (0...n).map { generate1(x) }.join when "ci" s, rest = args fail rest if rest s.chars.map{|x|[x.upcase, x.downcase].sample}.join when "cs" s, rest = args fail rest if rest s when "char-range" l, r = args fail rest if rest (rand(r.ord-l.ord+1)+l.ord).chr(Encoding::UTF_8) when "prose" # ["prose", text] fail "prose not implemented #{what.inspect}" when "im" warn "abnftt-style inline module ignored #{what.inspect}" '' else fail [op, args].inspect end else fail end end
to_treetop(modname)
click to toggle source
# File lib/abnftt.rb, line 128 def to_treetop(modname) <<~EOS # Encoding: UTF-8 grammar #{modname} #{rules.map {|k, v| to_treetop0(k, v)}.join} end EOS end
to_treetop0(k, v)
click to toggle source
# File lib/abnftt.rb, line 136 def to_treetop0(k, v) <<~EOS rule #{to_treetop1(k)} #{to_treetop1(v)} end EOS end
to_treetop1(ast)
click to toggle source
# File lib/abnftt.rb, line 147 def to_treetop1(ast) case ast when String FIXUP_NAMES[ast].gsub("-", "_") when Array case ast[0] when "alt" # ["alt", *a] "(#{ast[1..-1].map {|x| to_treetop1(x)}.join(" / ")})" when "seq" # ["seq", *a] "(#{ast[1..-1].map {|x| to_treetop1(x)}.join(" ")})" when "rep" # ["rep", s, e, a] t = to_treetop1(ast[3]) || "@@@" case [ast[1], ast[2]] when [0, 1] t + "?" when [0, true] t + "*" when [1, true] t + "+" else t + " #{ast[1]}..#{ast[2] == true ? '' : ast[2]}" end when "prose" # ["prose", text] fail "prose not implemented #{ast.inspect}" when "ci" # ["ci", text] s = ast[1] if s =~ /\A[^A-Za-z]*\z/ s.inspect else s.inspect << "i" # could do this always, but reduce noise end when "cs" # ["cs", text] ast[1].inspect when "char-range" # ["char-range", c1, c2] c1 = Regexp.quote(ast[1]) c2 = Regexp.quote(ast[2]) "[#{c1}-#{c2}]" # XXX does that always work when "im" # ["im", a, text] to_treetop1(ast[1]) + " " + ast[2] else fail "to_treetop(#{ast.inspect})" end else fail "to_treetop(#{ast.inspect})" end end
validate(s)
click to toggle source
# File lib/abnftt.rb, line 197 def validate(s) @parser ||= Treetop.load_from_string(to_treetop("ABNF_Mod" << (@@gensym += 1).to_s)) parser_instance ||= @parser.new unless result1 = parser_instance.parse(s) fail self.class.reason(parser_instance, s) end end