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?) ?
[ "[0;0m", "[1;30m", "[0;32m", "[1;33m", "[0;34m", "[0;37m" ] :
[ '', '', '', '', '', '' ]
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"