diff --git a/lib/kpeg/code_generator.rb b/lib/kpeg/code_generator.rb index 66ca84c..bb9709d 100644 --- a/lib/kpeg/code_generator.rb +++ b/lib/kpeg/code_generator.rb @@ -10,6 +10,14 @@ def initialize(name, gram, debug=false) @saves = 0 @output = nil @standalone = false + @indent = 0 + @code = '' + end + + def add(str, indent=0) + @indent -= 2 if indent < 0 + @code << (' ' * @indent) + str + @indent += 2 if indent > 0 end attr_accessor :standalone @@ -35,17 +43,18 @@ def reset_saves end def output_op(code, op) + @code = code case op when Dot - code << " _tmp = get_byte\n" + add " _tmp = get_byte\n" when LiteralString - code << " _tmp = match_string(#{op.string.dump})\n" + add " _tmp = match_string(#{op.string.dump})\n" when LiteralRegexp - code << " _tmp = scan(/\\A#{op.regexp}/)\n" + add " _tmp = scan(/\\A#{op.regexp}/)\n" when CharRange if op.start.bytesize == 1 and op.fin.bytesize == 1 - code << " _tmp = get_byte\n" - code << " if _tmp\n" + add " _tmp = get_byte\n" + add " if _tmp\n", +1 if op.start.respond_to? :getbyte left = op.start.getbyte 0 @@ -55,167 +64,167 @@ def output_op(code, op) right = op.fin[0] end - code << " unless _tmp >= #{left} and _tmp <= #{right}\n" - code << " fail_range('#{op.start}', '#{op.fin}')\n" - code << " _tmp = nil\n" - code << " end\n" - code << " end\n" + add " unless _tmp >= #{left} and _tmp <= #{right}\n" + add " fail_range('#{op.start}', '#{op.fin}')\n" + add " _tmp = nil\n" + add " end\n" + add " end\n", -1 else raise "Unsupported char range - #{op.inspect}" end when Choice ss = save() - code << "\n #{ss} = self.pos\n" - code << " while true # choice\n" + add "\n #{ss} = self.pos\n" + add " while true # choice\n", +1 op.ops.each_with_index do |n,idx| output_op code, n - code << " break if _tmp\n" - code << " self.pos = #{ss}\n" + add " break if _tmp\n" + add " self.pos = #{ss}\n" if idx == op.ops.size - 1 - code << " break\n" + add " break\n" end end - code << " end # end choice\n\n" + add " end # end choice\n\n", -1 when Multiple ss = save() if op.min == 0 and op.max == 1 - code << " #{ss} = self.pos\n" + add " #{ss} = self.pos\n" output_op code, op.op if op.save_values - code << " @result = nil unless _tmp\n" + add " @result = nil unless _tmp\n" end - code << " unless _tmp\n" - code << " _tmp = true\n" - code << " self.pos = #{ss}\n" - code << " end\n" + add " unless _tmp\n" + add " _tmp = true\n" + add " self.pos = #{ss}\n" + add " end\n" elsif op.min == 0 and !op.max if op.save_values - code << " _ary = []\n" + add " _ary = []\n" end - code << " while true\n" + add " while true\n", +1 output_op code, op.op if op.save_values - code << " _ary << @result if _tmp\n" + add " _ary << @result if _tmp\n" end - code << " break unless _tmp\n" - code << " end\n" - code << " _tmp = true\n" + add " break unless _tmp\n" + add " end\n", -1 + add " _tmp = true\n" if op.save_values - code << " @result = _ary\n" + add " @result = _ary\n" end elsif op.min == 1 and !op.max - code << " #{ss} = self.pos\n" + add " #{ss} = self.pos\n" if op.save_values - code << " _ary = []\n" + add " _ary = []\n" end output_op code, op.op - code << " if _tmp\n" + add " if _tmp\n", +1 if op.save_values - code << " _ary << @result\n" + add " _ary << @result\n" end - code << " while true\n" - code << " " + add " while true\n", +1 + add " " output_op code, op.op if op.save_values - code << " _ary << @result if _tmp\n" + add " _ary << @result if _tmp\n" end - code << " break unless _tmp\n" - code << " end\n" - code << " _tmp = true\n" + add " break unless _tmp\n" + add " end\n" + add " _tmp = true\n" if op.save_values - code << " @result = _ary\n" + add " @result = _ary\n" end - code << " else\n" - code << " self.pos = #{ss}\n" - code << " end\n" + add " else\n" + add " self.pos = #{ss}\n" + add " end\n" else - code << " #{ss} = self.pos\n" - code << " _count = 0\n" - code << " while true\n" - code << " " + add " #{ss} = self.pos\n" + add " _count = 0\n" + add " while true\n", +1 + add " " output_op code, op.op - code << " if _tmp\n" - code << " _count += 1\n" - code << " break if _count == #{op.max}\n" - code << " else\n" - code << " break\n" - code << " end\n" - code << " end\n" - code << " if _count >= #{op.min}\n" - code << " _tmp = true\n" - code << " else\n" - code << " self.pos = #{ss}\n" - code << " _tmp = nil\n" - code << " end\n" + add " if _tmp\n" + add " _count += 1\n" + add " break if _count == #{op.max}\n" + add " else\n" + add " break\n" + add " end\n" + add " end\n", -1 + add " if _count >= #{op.min}\n" + add " _tmp = true\n" + add " else\n" + add " self.pos = #{ss}\n" + add " _tmp = nil\n" + add " end\n" end when Sequence ss = save() - code << "\n #{ss} = self.pos\n" - code << " while true # sequence\n" + add "\n #{ss} = self.pos\n" + add " while true # sequence\n", +1 op.ops.each_with_index do |n, idx| output_op code, n if idx == op.ops.size - 1 - code << " unless _tmp\n" - code << " self.pos = #{ss}\n" - code << " end\n" - code << " break\n" + add " unless _tmp\n" + add " self.pos = #{ss}\n" + add " end\n" + add " break\n" else - code << " unless _tmp\n" - code << " self.pos = #{ss}\n" - code << " break\n" - code << " end\n" + add " unless _tmp\n" + add " self.pos = #{ss}\n" + add " break\n" + add " end\n" end end - code << " end # end sequence\n\n" + add " end # end sequence\n\n", -1 when AndPredicate ss = save() - code << " #{ss} = self.pos\n" + add " #{ss} = self.pos\n" if op.op.kind_of? Action - code << " _tmp = begin; #{op.op.action}; end\n" + add " _tmp = begin; #{op.op.action}; end\n" else output_op code, op.op end - code << " self.pos = #{ss}\n" + add " self.pos = #{ss}\n" when NotPredicate ss = save() - code << " #{ss} = self.pos\n" + add " #{ss} = self.pos\n" if op.op.kind_of? Action - code << " _tmp = begin; #{op.op.action}; end\n" + add " _tmp = begin; #{op.op.action}; end\n" else output_op code, op.op end - code << " _tmp = _tmp ? nil : true\n" - code << " self.pos = #{ss}\n" + add " _tmp = _tmp ? nil : true\n" + add " self.pos = #{ss}\n" when RuleReference - code << " _tmp = apply(:#{method_name op.rule_name})\n" + add " _tmp = apply(:#{method_name op.rule_name})\n" when InvokeRule - code << " _tmp = #{method_name op.rule_name}()\n" + add " _tmp = #{method_name op.rule_name}()\n" when Tag if op.tag_name and !op.tag_name.empty? output_op code, op.op - code << " #{op.tag_name} = @result\n" + add " #{op.tag_name} = @result\n" else output_op code, op.op end when Action - code << " @result = begin; " - code << op.action << "; end\n" + add " @result = begin; " + add op.action << "; end\n" if @debug - code << " puts \" => \" #{op.action.dump} \" => \#{@result.inspect} \\n\"\n" + add " puts \" => \" #{op.action.dump} \" => \#{@result.inspect} \\n\"\n" end - code << " _tmp = true\n" + add " _tmp = true\n" when Collect - code << " _text_start = self.pos\n" + add " _text_start = self.pos\n" output_op code, op.op - code << " if _tmp\n" - code << " text = get_text(_text_start)\n" - code << " end\n" + add " if _tmp\n" + add " text = get_text(_text_start)\n" + add " end\n" else raise "Unknown op - #{op.class}" end diff --git a/test/test_kpeg_code_generator.rb b/test/test_kpeg_code_generator.rb index 456e400..3bb7c31 100644 --- a/test/test_kpeg_code_generator.rb +++ b/test/test_kpeg_code_generator.rb @@ -4,6 +4,20 @@ require 'stringio' class TestKPegCodeGenerator < Test::Unit::TestCase + @@i=0 + def compare_str(str1, str2) + stripped1 = str1.gsub(/\n[ \t]+/, "\n") + stripped2 = str2.gsub(/\n[ \t]+/, "\n") + if stripped1 != stripped2 + puts str1 + puts '-' * 50 + puts str2 + @@i+=1 + File.open("/tmp/bad#{@@i}", "w"){|f| f.puts str2} if $DEBUG + end + assert_equal stripped1, stripped2 + end + def test_dot gram = KPeg.grammar do |g| g.root = g.dot @@ -107,7 +121,7 @@ def _root cg = KPeg::CodeGenerator.new "Test", gram - assert_equal str, cg.output + compare_str str, cg.output assert cg.parse("z") assert cg.parse("a") @@ -154,7 +168,7 @@ def _root cg = KPeg::CodeGenerator.new "Test", gram - assert_equal str, cg.output + compare_str str, cg.output assert cg.parse("ahello") assert cg.parse("zhello") @@ -193,7 +207,7 @@ def _root cg = KPeg::CodeGenerator.new "Test", gram - assert_equal str, cg.output + compare_str str, cg.output assert cg.parse("hello") assert cg.parse("world") @@ -283,7 +297,7 @@ def _root cg = KPeg::CodeGenerator.new "Test", gram - assert_equal str, cg.output + compare_str str, cg.output code = cg.make("hellohellohello") assert code.parse @@ -336,7 +350,7 @@ def _root cg = KPeg::CodeGenerator.new "Test", gram - assert_equal str, cg.output + compare_str str, cg.output code = cg.make("hellohello") assert code.parse @@ -402,7 +416,7 @@ def _root cg = KPeg::CodeGenerator.new "Test", gram - assert_equal str, cg.output + compare_str str, cg.output end def test_seq @@ -439,7 +453,7 @@ def _root cg = KPeg::CodeGenerator.new "Test", gram - assert_equal str, cg.output + compare_str str, cg.output end def test_seq_resets_pos @@ -479,7 +493,7 @@ def _root cg = KPeg::CodeGenerator.new "Test", gram - assert_equal str, cg.output + compare_str str, cg.output code = cg.make("hello") assert code.parse @@ -512,7 +526,7 @@ def _root cg = KPeg::CodeGenerator.new "Test", gram - assert_equal str, cg.output + compare_str str, cg.output code = cg.make("hello") assert code.parse @@ -547,7 +561,7 @@ def _root cg = KPeg::CodeGenerator.new "Test", gram - assert_equal str, cg.output + compare_str str, cg.output code = cg.make("hello") assert !code.parse @@ -581,7 +595,7 @@ def _root cg = KPeg::CodeGenerator.new "Test", gram - assert_equal str, cg.output + compare_str str, cg.output code = cg.make("hello") assert code.parse @@ -621,7 +635,7 @@ def _root cg = KPeg::CodeGenerator.new "Test", gram - assert_equal str, cg.output + compare_str str, cg.output assert cg.parse("hello") end @@ -653,7 +667,7 @@ def _root cg = KPeg::CodeGenerator.new "Test", gram - assert_equal str, cg.output + compare_str str, cg.output assert cg.parse("hello") end @@ -679,7 +693,7 @@ def _root cg = KPeg::CodeGenerator.new "Test", gram - assert_equal str, cg.output + compare_str str, cg.output end def test_noname_tag @@ -702,7 +716,7 @@ def _root cg = KPeg::CodeGenerator.new "Test", gram - assert_equal str, cg.output + compare_str str, cg.output end def test_tag_maybe @@ -721,21 +735,21 @@ def _hello _save = self.pos while true # sequence - _text_start = self.pos - _tmp = match_string("hello") - if _tmp - text = get_text(_text_start) - end - unless _tmp - self.pos = _save + _text_start = self.pos + _tmp = match_string("hello") + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + @result = begin; text; end + _tmp = true + unless _tmp + self.pos = _save + end break - end - @result = begin; text; end - _tmp = true - unless _tmp - self.pos = _save - end - break end # end sequence return _tmp @@ -746,24 +760,24 @@ def _root _save = self.pos while true # sequence - _save1 = self.pos - _tmp = apply(:_hello) - @result = nil unless _tmp - unless _tmp + _save1 = self.pos + _tmp = apply(:_hello) + @result = nil unless _tmp + unless _tmp + _tmp = true + self.pos = _save1 + end + lots = @result + unless _tmp + self.pos = _save + break + end + @result = begin; lots; end _tmp = true - self.pos = _save1 - end - lots = @result - unless _tmp - self.pos = _save + unless _tmp + self.pos = _save + end break - end - @result = begin; lots; end - _tmp = true - unless _tmp - self.pos = _save - end - break end # end sequence return _tmp @@ -773,7 +787,7 @@ def _root cg = KPeg::CodeGenerator.new "Test", gram - assert_equal str, cg.output + compare_str str, cg.output code = cg.make("hello") assert code.parse @@ -801,21 +815,21 @@ def _hello _save = self.pos while true # sequence - _text_start = self.pos - _tmp = match_string("hello") - if _tmp - text = get_text(_text_start) - end - unless _tmp - self.pos = _save + _text_start = self.pos + _tmp = match_string("hello") + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + @result = begin; text; end + _tmp = true + unless _tmp + self.pos = _save + end break - end - @result = begin; text; end - _tmp = true - unless _tmp - self.pos = _save - end - break end # end sequence return _tmp @@ -826,25 +840,25 @@ def _root _save = self.pos while true # sequence - _ary = [] - while true - _tmp = apply(:_hello) - _ary << @result if _tmp - break unless _tmp - end - _tmp = true - @result = _ary - lots = @result - unless _tmp - self.pos = _save + _ary = [] + while true + _tmp = apply(:_hello) + _ary << @result if _tmp + break unless _tmp + end + _tmp = true + @result = _ary + lots = @result + unless _tmp + self.pos = _save + break + end + @result = begin; lots; end + _tmp = true + unless _tmp + self.pos = _save + end break - end - @result = begin; lots; end - _tmp = true - unless _tmp - self.pos = _save - end - break end # end sequence return _tmp @@ -854,7 +868,7 @@ def _root cg = KPeg::CodeGenerator.new "Test", gram - assert_equal str, cg.output + compare_str str, cg.output code = cg.make("hellohello") assert code.parse @@ -885,21 +899,21 @@ def _hello _save = self.pos while true # sequence - _text_start = self.pos - _tmp = match_string("hello") - if _tmp - text = get_text(_text_start) - end - unless _tmp - self.pos = _save + _text_start = self.pos + _tmp = match_string("hello") + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + @result = begin; text; end + _tmp = true + unless _tmp + self.pos = _save + end break - end - @result = begin; text; end - _tmp = true - unless _tmp - self.pos = _save - end - break end # end sequence return _tmp @@ -910,33 +924,33 @@ def _root _save = self.pos while true # sequence - _save1 = self.pos - _ary = [] - _tmp = apply(:_hello) - if _tmp - _ary << @result - while true - _tmp = apply(:_hello) - _ary << @result if _tmp - break unless _tmp - end - _tmp = true - @result = _ary - else - self.pos = _save1 - end - lots = @result - unless _tmp - self.pos = _save - break - end - @result = begin; lots; end - _tmp = true - unless _tmp - self.pos = _save - end - break - end # end sequence + _save1 = self.pos + _ary = [] + _tmp = apply(:_hello) + if _tmp + _ary << @result + while true + _tmp = apply(:_hello) + _ary << @result if _tmp + break unless _tmp + end + _tmp = true + @result = _ary + else + self.pos = _save1 + end + lots = @result + unless _tmp + self.pos = _save + break + end + @result = begin; lots; end + _tmp = true + unless _tmp + self.pos = _save + end + break + end # end sequence return _tmp end @@ -945,7 +959,7 @@ def _root cg = KPeg::CodeGenerator.new "Test", gram - assert_equal str, cg.output + compare_str str, cg.output code = cg.make("hellohello") assert code.parse @@ -980,7 +994,7 @@ def _root cg = KPeg::CodeGenerator.new "Test", gram - assert_equal str, cg.output + compare_str str, cg.output code = cg.make("") assert code.parse @@ -1002,21 +1016,21 @@ def _root _save = self.pos while true # sequence - _text_start = self.pos - _tmp = match_string("hello") - if _tmp - text = get_text(_text_start) - end - unless _tmp - self.pos = _save + _text_start = self.pos + _tmp = match_string("hello") + if _tmp + text = get_text(_text_start) + end + unless _tmp + self.pos = _save + break + end + @result = begin; text ; end + _tmp = true + unless _tmp + self.pos = _save + end break - end - @result = begin; text ; end - _tmp = true - unless _tmp - self.pos = _save - end - break end # end sequence return _tmp @@ -1026,7 +1040,7 @@ def _root cg = KPeg::CodeGenerator.new "Test", gram - assert_equal str, cg.output + compare_str str, cg.output code = cg.make("hello") assert code.parse @@ -1077,7 +1091,7 @@ def _root cg = KPeg::CodeGenerator.new "Test", gram - assert_equal str, cg.output + compare_str str, cg.output assert cg.parse("hello") end