lib/raabro.rb in raabro-1.1.3 vs lib/raabro.rb in raabro-1.1.4

- old
+ new

@@ -1,7 +1,7 @@ #-- -# Copyright (c) 2015-2016, John Mettraux, jmettraux@gmail.com +# Copyright (c) 2015-2017, John Mettraux, jmettraux@gmail.com # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell @@ -23,11 +23,11 @@ #++ module Raabro - VERSION = '1.1.3' + VERSION = '1.1.4' class Input attr_accessor :string, :offset attr_reader :options @@ -53,10 +53,15 @@ def tring(l=-1) l < 0 ? @string[@offset..l] : @string[@offset, l] end + + def at(i) + + @string[i, 1] + end end class Tree attr_accessor :name, :input @@ -179,10 +184,78 @@ def even_children cs = []; @children.each_with_index { |c, i| cs << c if i.even? }; cs end + + def extract_error + +#Raabro.pp(self, colors: true) + err_tree, stack = lookup_error || lookup_all_error + + line, column = line_and_column(err_tree.offset) + + err_message = + if stack + path = stack + .compact.reverse.take(3).reverse + .collect(&:inspect).join('/') + "parsing failed .../#{path}" + else + "parsing failed, not all input was consumed" + end + visual = + visual(line, column) + + [ line, column, err_tree.offset, err_message, visual ] + end + + def lookup_error(stack=[]) + +#print "le(): "; Raabro.pp(self, colors: true) + return nil if @result != 0 + return [ self, stack ] if @children.empty? + @children.each { |c| + es = c.lookup_error(stack.dup.push(self.name)) + return es if es } + nil + end + + # Not "lookup all errors" but "lookup all error", in other + # words lookup the point up until which the parser stopped (not + # consuming all the input) + # + def lookup_all_error + +#print "lae(): "; Raabro.pp(self, colors: true) + @children.each { |c| return [ c, nil ] if c.result == 0 } + @children.reverse.each { |c| es = c.lookup_all_error; return es if es } + nil + end + + def line_and_column(offset) + + line = 1 + column = 0 + + (0..offset).each do |off| + + column += 1 + next unless @input.at(off) == "\n" + + line += 1 + column = 0 + end + + [ line, column ] + end + + def visual(line, column) + + @input.string.split("\n")[line - 1] + "\n" + + ' ' * (column - 1) + '^---' + end end module ModuleMethods def _match(name, input, parter, regex_or_string) @@ -470,19 +543,31 @@ _parse(root, Raabro::Input.new(input, opts)) else all(nil, Raabro::Input.new(input, opts), root) end + return reparse_for_error(input, opts, t) if opts[:error] && t.result != 1 return nil if opts[:prune] != false && t.result != 1 t = t.children.first if t.parter == :all return rewrite(t) if opts[:rewrite] != false t end + def reparse_for_error(input, opts, t) + + t = + opts[:prune] == false ? + t : + parse(input, opts.merge(error: false, rewrite: false, prune: false)) +#Raabro.pp(t, colours: true) + + t.extract_error + end + def rewrite_(tree) t = tree.lookup(nil) t ? rewrite(t) : nil @@ -518,14 +603,20 @@ # Red 0;31 Light Red 1;31 # Purple 0;35 Light Purple 1;35 # Brown 0;33 Yellow 1;33 # Light Gray 0;37 White 1;37 - def self.pp(tree, depth=0) + def self.pp(tree, depth=0, opts={}) + fail ArgumentError.new( + 'tree is not an instance of Raabro::Tree' + ) unless tree.is_a?(Raabro::Tree) + + depth, opts = 0, depth if depth.is_a?(Hash) + _rs, _dg, _gn, _yl, _bl, _lg = - $stdout.tty? ? + (opts[:colors] || opts[:colours] || $stdout.tty?) ? [ "", "", "", "", "", "" ] : [ '', '', '', '', '', '' ] lc = tree.result == 1 ? _gn : _dg nc = tree.result == 1 ? _bl : _lg @@ -552,10 +643,10 @@ print "#{lc}#{tree.result}" print " #{nc}#{tree.name.inspect} #{lc}#{tree.offset},#{tree.length}" print str print "#{_rs}\n" - tree.children.each { |c| self.pp(c, depth + 1) } + tree.children.each { |c| self.pp(c, depth + 1, opts) } if depth == 0 print _dg print "input ln: #{tree.input.string.length}, tree ln: #{tree.length} " print "---t\n"