pax_global_header00006660000000000000000000000064137367263300014524gustar00rootroot0000000000000052 comment=aaf1aa27e7bfb86a63339f4ebf3938ff2e0c0258 raabro-1.4.0/000077500000000000000000000000001373672633000127745ustar00rootroot00000000000000raabro-1.4.0/.gitignore000066400000000000000000000002461373672633000147660ustar00rootroot00000000000000 *.swp .vimrc .viminfo pkg/ .ruby-version #.rspec .vimrc .viminfo .vimmarks .vimspec .vimgrep *.swp .errors .rspec.out .bxsinfo.yaml .bxsenvs.yaml Gemfile.lock raabro-1.4.0/.rspec000066400000000000000000000000401373672633000141030ustar00rootroot00000000000000--colour --format documentation raabro-1.4.0/.travis.yml000066400000000000000000000007141373672633000151070ustar00rootroot00000000000000 language: ruby rvm: #- 1.8.7 # no, since it doesn't get fun(a, *b, c) or fun0\n.fun1 #- 1.9.3 # Travis broken September 2017 #- 2.1.1 - 2.2.2 - 2.3.1 - 2.4.1 - 2.5.1 #- jruby-18mode - jruby-19mode - jruby-20mode #matrix: # include: # - rvm: jruby-9.1.13.0 # #- env: JRUBY_OPTS="--profile.api" #before_install: gem install bundler script: bundle exec rspec branches: only: - master #except: # - master cache: bundler raabro-1.4.0/CHANGELOG.md000066400000000000000000000037301373672633000146100ustar00rootroot00000000000000 # raabro CHANGELOG.md ## raabro 1.4.0 released 2020-10-06 * Ensure that jseq, for n elts, parses n-1 separators * Introduce Tree #symbol, #symbod, #strind and #strinpd ## raabro 1.3.3 released 2020-09-24 * Merge Henrik's rewrite_ optimization ## raabro 1.3.2 released 2020-09-24 * Make a tiny rewrite_ optimization ## raabro 1.3.1 released 2020-05-10 * Add '!' (not) seq quantifier ## raabro 1.3.0 released 2020-05-10 * Add `nott` parser element * Add Tree#strinp and #strim * Skip 1.2.0 to align on http://github.com/jmettraux/jaabro ## raabro 1.1.6 released 2018-06-22 * Remove unused `add` var, gh-2, thanks to https://github.com/utilum ## raabro 1.1.5 released 2017-08-19 * Default name to nil for Tree#subgather, #gather, #sublookup, and #lookup ## raabro 1.1.4 released 2017-08-17 * fail with ArgumentError if Raabro.pp input is not a Raabro::Tree * parse(x, error: true) will produce an error message `[ line, column, offset, err_message, err_visual ]` ## raabro 1.1.3 released 2016-07-11 * display `>nonstring(14)<` in Raabro.pp * add "tears" to Raabro.pp ## raabro 1.1.2 released 2016-04-04 * add Raabro.pp(tree) ## raabro 1.1.1 released 2016-04-03 * Tree#clast ## raabro 1.1.0 released 2016-02-09 * many improvements * unlock custom `rewrite(t)` ## raabro 1.0.5 released 2015-09-25 * allow for .parse(s, debug: 1 to 3) * drop complications in _narrow(parser) ## raabro 1.0.4 released 2015-09-24 * provide a default .rewrite implementation ## raabro 1.0.3 released 2015-09-23 * drop the shrink! concept ## raabro 1.0.2 released 2015-09-23 * don't let parse() shrink tree when prune: false * let parse() return tree anyway when prune: false * add parse(s, rewrite: false) option ## raabro 1.0.1 released 2015-09-23 * take last parser as default :root * provide default .parse for modules including Raabro ## raabro 1.0.0 released 2015-09-23 * first complete (hopefully) release ## raabro 0.9.0 * initial push to RubyGems raabro-1.4.0/CREDITS.md000066400000000000000000000005741373672633000144210ustar00rootroot00000000000000 # raabro credits * Henryk Nyh https://github.com/henrik optimized rewrite_, gh-6 * Utilum https://github.com/utilum removed unused var * John Mettraux https://github.com/jmettraux author and maintainer ## aabro and jaabro credits Thanks to all the people who contributed to aabro and jaabro as well. * https://github.com/flon-io/aabro * https://github.com/jmettraux/jaabro raabro-1.4.0/Gemfile000066400000000000000000000000751373672633000142710ustar00rootroot00000000000000 source 'https://rubygems.org' #gem 'tzinfo-data' gemspec raabro-1.4.0/LICENSE.txt000066400000000000000000000021171373672633000146200ustar00rootroot00000000000000 Copyright (c) 2015-2020, 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 copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Made in Japan. raabro-1.4.0/Makefile000066400000000000000000000016571373672633000144450ustar00rootroot00000000000000 ## gem tasks ## NAME = \ $(shell ruby -e "s = eval(File.read(Dir['*.gemspec'][0])); puts s.name") VERSION = \ $(shell ruby -e "s = eval(File.read(Dir['*.gemspec'][0])); puts s.version") count_lines: find lib -name "*.rb" | xargs cat | ruby -e "p STDIN.readlines.count { |l| l = l.strip; l[0, 1] != '#' && l != '' }" find spec -name "*_spec.rb" | xargs cat | ruby -e "p STDIN.readlines.count { |l| l = l.strip; l[0, 1] != '#' && l != '' }" cl: count_lines gemspec_validate: @echo "---" ruby -e "s = eval(File.read(Dir['*.gemspec'].first)); p s.validate" @echo "---" name: gemspec_validate @echo "$(NAME) $(VERSION)" cw: find lib -name "*.rb" -exec ruby -cw {} \; build: gemspec_validate gem build $(NAME).gemspec mkdir -p pkg mv $(NAME)-$(VERSION).gem pkg/ push: build gem push --otp "$(OTP)" pkg/$(NAME)-$(VERSION).gem spec: bundle exec rspec test: spec .PHONY: count_lines gemspec_validate name cw build push spec raabro-1.4.0/README.md000066400000000000000000000203001373672633000142460ustar00rootroot00000000000000 # raabro [![Build Status](https://secure.travis-ci.org/floraison/raabro.svg)](http://travis-ci.org/floraison/raabro) [![Gem Version](https://badge.fury.io/rb/raabro.svg)](http://badge.fury.io/rb/raabro) A very dumb PEG parser library. Son to [aabro](https://github.com/flon-io/aabro), grandson to [neg](https://github.com/jmettraux/neg), grand-grandson to [parslet](https://github.com/kschiess/parslet). There is also a javascript version [jaabro](https://github.com/jmettraux/jaabro). ## a sample parser/rewriter You use raabro by providing the parsing rules, then some rewrite rules. The parsing rules make use of the raabro basic parsers `seq`, `alt`, `str`, `rex`, `eseq`, ... The rewrite rules match names passed as first argument to the basic parsers to rewrite the resulting parse trees. ```ruby require 'raabro' module Fun include Raabro # parse # # Last function is the root, "i" stands for "input". def pstart(i); rex(nil, i, /\(\s*/); end def pend(i); rex(nil, i, /\)\s*/); end # parenthese start and end, including trailing white space def comma(i); rex(nil, i, /,\s*/); end # a comma, including trailing white space def num(i); rex(:num, i, /-?[0-9]+\s*/); end # name is :num, a positive or negative integer def args(i); eseq(nil, i, :pstart, :exp, :comma, :pend); end # a set of :exp, beginning with a (, punctuated by commas and ending with ) def funame(i); rex(nil, i, /[a-z][a-z0-9]*/); end def fun(i); seq(:fun, i, :funame, :args); end # name is :fun, a function composed of a function name # followed by arguments def exp(i); alt(nil, i, :fun, :num); end # an expression is either (alt) a function or a number # rewrite # # Names above (:num, :fun, ...) get a rewrite_xxx function. # "t" stands for "tree". def rewrite_exp(t); rewrite(t.children[0]); end def rewrite_num(t); t.string.to_i; end def rewrite_fun(t) funame, args = t.children [ funame.string ] + args.gather.collect { |e| rewrite(e) } # # #gather collect all the children in a tree that have # a name, in this example, names can be :exp, :num, :fun end end p Fun.parse('mul(1, 2)') # => ["mul", 1, 2] p Fun.parse('mul(1, add(-2, 3))') # => ["mul", 1, ["add", -2, 3]] p Fun.parse('mul (1, 2)') # => nil (doesn't accept a space after the function name) ``` This sample is available at: [doc/readme0.rb](doc/readme0.rb). ## custom rewrite() By default, a parser gets a `rewrite(t)` that looks at the parse tree node names and calls the corresponding `rewrite_{node_name}()`. It's OK to provide a custom `rewrite(t)` function. ```ruby module Hello include Raabro def hello(i); str(:hello, i, 'hello'); end def rewrite(t) [ :ok, t.string ] end end ``` ## basic parsers One makes a parser by composing basic parsers, for example: ```ruby def args(i); eseq(:args, i, :pa, :exp, :com, :pz); end def funame(i); rex(:funame, i, /[a-z][a-z0-9]*/); end def fun(i); seq(:fun, i, :funame, :args); end ``` where the `fun` parser is a sequence combining the `funame` parser then the `args` one. `:fun` (the first argument to the basic parser `seq`) will be the name of the resulting (local) parse tree. Below is a list of the basic parsers provided by Raabro. The first parameter to the basic parser is the name used by rewrite rules. The second parameter is a `Raabro::Input` instance, mostly a wrapped string. ```ruby def str(name, input, string) # matching a string def rex(name, input, regex_or_string) # matching a regexp # no need for ^ or \A, checks the match occurs at current offset def seq(name, input, *parsers) # a sequence of parsers def alt(name, input, *parsers) # tries the parsers returns as soon as one succeeds def altg(name, input, *parsers) # tries all the parsers, returns with the longest match def rep(name, input, parser, min, max=0) # repeats the the wrapped parser def nott(name, input, parser) # succeeds if the wrapped parser fails, fails if it succeeds def ren(name, input, parser) # renames the output of the wrapped parser def jseq(name, input, eltpa, seppa) # # seq(name, input, eltpa, seppa, eltpa, seppa, eltpa, seppa, ...) # # a sequence of `eltpa` parsers separated (joined) by `seppa` parsers def eseq(name, input, startpa, eltpa, seppa, endpa) # # seq(name, input, startpa, eltpa, seppa, eltpa, seppa, ..., endpa) # # a sequence of `eltpa` parsers separated (joined) by `seppa` parsers # preceded by a `startpa` parser and followed by a `endpa` parser ``` ## the `seq` parser and its quantifiers `seq` is special, it understands "quantifiers": `'?'`, `'+'` or `'*'`. They make behave `seq` a bit like a classical regex. The `'!'` (bang, not) quantifier is explained at the end of this section. ```ruby module CartParser include Raabro def fruit(i) rex(:fruit, i, /(tomato|apple|orange)/) end def vegetable(i) rex(:vegetable, i, /(potato|cabbage|carrot)/) end def cart(i) seq(:cart, i, :fruit, '*', :vegetable, '*') end # zero or more fruits followed by zero or more vegetables end ``` (Yes, this sample parser parses string like "appletomatocabbage", it's not very useful, but I hope you get the point about `.seq`) The `'!'` (bang, not) quantifier is a kind of "negative lookahead". ```ruby def menu(i) seq(:menu, i, :mise_en_bouche, :main, :main, '!', :dessert) end ``` Lousy example, but here a main cannot follow a main. ## trees An instance of `Raabro::Tree` is passed to `rewrite()` and `rewrite_{name}()` functions. The most useful methods of this class are: ```ruby class Raabro::Tree # Look for the first child or sub-child with the given name. # If the given name is nil, looks for the first child with a name (not nil). # def sublookup(name=nil) # Gathers all the children or sub-children with the given name. # If the given name is nil, gathers all the children with a name (not nil). # When a child matches, does not pursue gathering from the children of the # matching child. # def subgather(name=nil) end ``` I'm using "child or sub-child" instead of "descendant" because once a child or sub-child matches, those methods do not consider the children or sub-children of that matching entity. Here is a closeup on the rewrite functions of the sample parser at [doc/readme1.rb](doc/readme1.rb) (extracted from an early version of [floraison/dense](https://github.com/floraison/dense)): ```ruby require 'raabro' module PathParser include Raabro # (...) def rewrite_name(t); t.string; end def rewrite_off(t); t.string.to_i; end def rewrite_index(t); rewrite(t.sublookup); end def rewrite_path(t); t.subgather(:index).collect { |tt| rewrite(tt) }; end end ``` Where `rewrite_index(t)` returns the result of the rewrite of the first of its children that has a name and `rewrite_path(t)` collects the result of the rewrite of all of its children that have the "index" name. ## errors By default, a parser will return nil when it cannot successfully parse the input. For example, given the above [`Fun` parser](#a-sample-parserrewriter), parsing some truncated input would yield `nil`: ```ruby tree = Sample::Fun.parse('f(a, b') # yields `nil`... ``` One can reparse with `error: true` and receive an error array with the parse error details: ```ruby err = Sample::Fun.parse('f(a, b', error: true) # yields: # [ line, column, offest, error_message, error_visual ] [ 1, 4, 3, 'parsing failed .../:exp/:fun/:arg', "f(a, b\n ^---" ] ``` The last string in the error array looks like when printed out: ``` f(a, b ^--- ``` ### error when not all is consumed Consider the following toy parser: ```ruby module ToPlus include Raabro # parse def to_plus(input); rep(:tos, input, :to, 1); end # rewrite def rewrite(t); [ :ok, t.string ]; end end ``` ```ruby Sample::ToPlus.parse('totota') # yields nil since all the input was not parsed, "ta" is remaining Sample::ToPlus.parse('totota', all: false) # yields [ :ok, "toto" ] # and doesn't care about the remaining input "ta" Sample::ToPlus.parse('totota', error: true) # yields [ 1, 5, 4, "parsing failed, not all input was consumed", "totota\n ^---" ] ``` The last string in the error array looks like when printed out: ``` totota ^--- ``` ## LICENSE MIT, see [LICENSE.txt](LICENSE.txt) raabro-1.4.0/doc/000077500000000000000000000000001373672633000135415ustar00rootroot00000000000000raabro-1.4.0/doc/readme0.rb000066400000000000000000000021431373672633000154030ustar00rootroot00000000000000 # # A sample raabro parser/rewriter # # Thu Sep 24 06:18:57 JST 2015 # require 'raabro' module Fun include Raabro # parse # # Last function is the root, "i" stands for "input". def pa(i); rex(nil, i, /\(\s*/); end def pz(i); rex(nil, i, /\)\s*/); end def com(i); rex(nil, i, /,\s*/); end def num(i); rex(:num, i, /-?[0-9]+\s*/); end def args(i); eseq(nil, i, :pa, :exp, :com, :pz); end def funame(i); rex(nil, i, /[a-z][a-z0-9]*/); end def fun(i); seq(:fun, i, :funame, :args); end def exp(i); alt(nil, i, :fun, :num); end # rewrite # # Names above (:num, :fun, ...) get a rewrite_xxx function. # "t" stands for "tree". # # The trees with a nil name are handled by rewrite_(tree) a default # rewrite function def rewrite_num(t); t.string.to_i; end def rewrite_fun(t) [ t.children[0].string ] + t.children[1].odd_children.collect { |a| rewrite(a) } end end p Fun.parse('mul(1, 2)') # => ["mul", 1, 2] p Fun.parse('mul(1, add(-2, 3))') # => ["mul", 1, ["add", -2, 3]] p Fun.parse('mul (1, 2)') # => nil (doesn't accept a space after the function name) raabro-1.4.0/doc/readme1.rb000066400000000000000000000027431373672633000154120ustar00rootroot00000000000000 require 'raabro' module PathParser include Raabro # piece parsers bottom to top def dot(i); str(nil, i, '.'); end def bend(i); str(nil, i, ']'); end def bstart(i); str(nil, i, '['); end def dq(i); str(nil, i, '"'); end def sq(i); str(nil, i, "'"); end def name(i); rex(:name, i, /[a-z0-9_]+/i); end def off(i); rex(:off, i, /\d+/); end def dqname(i); seq(nil, i, :dq, :name, :dq); end def sqname(i); seq(nil, i, :sq, :name, :sq); end def bindex(i); alt(:index, i, :off, :dqname, :sqname); end def dindex(i); alt(:index, i, :off, :name); end def bracket_index(i); seq(nil, i, :bstart, :bindex, :bend); end def dot_index(i); seq(nil, i, :dot, :dindex); end def then_index(i); alt(nil, i, :dot_index, :bracket_index); end def start_index(i); alt(nil, i, :dindex, :bracket_index); end def path(i); seq(:path, i, :start_index, :then_index, '*'); end # rewrite parsed tree def rewrite_name(t); t.string; end def rewrite_off(t); t.string.to_i; end def rewrite_index(t); rewrite(t.sublookup); end def rewrite_path(t); t.subgather(:index).collect { |tt| rewrite(tt) }; end end p PathParser.parse('0.name') # => [ 0, 'name' ], p PathParser.parse('name.0') # => [ 'name', 0 ], p PathParser.parse('11[0]') # => [ 11, 0 ], p PathParser.parse("name['first']") # => [ 'name', 'first' ], p PathParser.parse('name["last"]') # => [ 'name', 'last' ], p PathParser.parse('name[0]') # => [ 'name', 0 ], p PathParser.parse('[0].name') # => [ 0, 'name' ], raabro-1.4.0/doc/test.rb000066400000000000000000000031251373672633000150460ustar00rootroot00000000000000 # # A sample raabro parser/rewriter # # Thu Sep 24 06:18:57 JST 2015 # require 'raabro' module Fun include Raabro # parse # # Last function is the root, "i" stands for "input". def pstart(i); rex(nil, i, /\(\s*/); end def pend(i); rex(nil, i, /\)\s*/); end # parenthese start and end, including trailing white space def comma(i); rex(nil, i, /,\s*/); end # a comma, including trailing white space def num(i); rex(:num, i, /-?[0-9]+\s*/); end # name is :num, a positive or negative integer def args(i); eseq(nil, i, :pstart, :exp, :comma, :pend); end # a set of :exp, beginning with a (, punctuated by commas and ending with ) def funame(i); rex(nil, i, /[a-z][a-z0-9]*/); end def fun(i); seq(:fun, i, :funame, :args); end # name is :fun, a function composed of a function name # followed by arguments def exp(i); alt(nil, i, :fun, :num); end # an expression is either (alt) a function or a number # rewrite # # Names above (:num, :fun, ...) get a rewrite_xxx function. # "t" stands for "tree". def rewrite_exp(t); rewrite(t.children[0]); end def rewrite_num(t); t.string.to_i; end def rewrite_fun(t) funame, args = t.children [ funame.string ] + args.gather.collect { |e| rewrite(e) } # # #gather collect all the children in a tree that have # a name, in this example, names can be :exp, :num, :fun end end p Fun.parse('mul(1, 2)') # => ["mul", 1, 2] p Fun.parse('mul(1, add(-2, 3))') # => ["mul", 1, ["add", -2, 3]] p Fun.parse('mul (1, 2)') # => nil (doesn't accept a space after the function name) raabro-1.4.0/lib/000077500000000000000000000000001373672633000135425ustar00rootroot00000000000000raabro-1.4.0/lib/raabro.rb000066400000000000000000000337361373672633000153510ustar00rootroot00000000000000# frozen_string_literal: true module Raabro VERSION = '1.4.0' class Input attr_accessor :string, :offset attr_reader :options def initialize(string, offset=0, options={}) @string = string @offset = offset.is_a?(Hash) ? 0 : offset @options = offset.is_a?(Hash) ? offset : options end def match(str_or_regex) if str_or_regex.is_a?(Regexp) m = @string[@offset..-1].match(str_or_regex) m && (m.offset(0).first == 0) ? m[0].length : false else # String or whatever responds to #to_s s = str_or_regex.to_s l = s.length @string[@offset, l] == s ? l : false end end 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 attr_accessor :result # ((-1 error,)) 0 nomatch, 1 success attr_accessor :offset, :length attr_accessor :parter, :children def initialize(name, parter, input) @result = 0 @name = name @parter = parter @input = input @offset = input.offset @length = 0 @children = [] end def c0; @children[0]; end def c1; @children[1]; end def c2; @children[2]; end def c3; @children[3]; end def c4; @children[4]; end def clast; @children.last; end def empty? @result == 1 && @length == 0 end def successful_children @children.select { |c| c.result == 1 } end def prune! @children = successful_children end def string; @input.string[@offset, @length]; end def strinp; string.strip; end alias strim strinp def nonstring(l=7); @input.string[@offset, l]; end def stringd; string.downcase; end alias strind stringd def stringpd; strinp.downcase; end alias strinpd stringpd def symbol; strinp.to_sym; end def symbold; symbol.downcase; end alias symbod symbold def lookup(name=nil) name = name ? name.to_s : nil return self if @name && name == nil return self if @name.to_s == name sublookup(name) end def sublookup(name=nil) @children.each { |c| if n = c.lookup(name); return n; end } nil end def gather(name=nil, acc=[]) name = name ? name.to_s : nil if (@name && name == nil) || (@name.to_s == name) acc << self else subgather(name, acc) end acc end def subgather(name=nil, acc=[]) @children.each { |c| c.gather(name, acc) } acc end def to_a(opts={}) opts = Array(opts).inject({}) { |h, e| h[e] = true; h } \ unless opts.is_a?(Hash) cn = if opts[:leaves] && (@result == 1) && @children.empty? string elsif opts[:children] != false @children.collect { |e| e.to_a(opts) } else @children.length end [ @name, @result, @offset, @length, @note, @parter, cn ] end def to_s(depth=0, io=StringIO.new) io.print "\n" if depth > 0 io.print ' ' * depth io.print "#{@result} #{@name.inspect} #{@offset},#{@length}" io.print result == 1 && children.size == 0 ? ' ' + string.inspect : '' @children.each { |c| c.to_s(depth + 1, io) } depth == 0 ? io.string : nil end def odd_children cs = []; @children.each_with_index { |c, i| cs << c if i.odd? }; cs end 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) r = Raabro::Tree.new(name, parter, input) if l = input.match(regex_or_string) r.result = 1 r.length = l input.offset += l end r end def str(name, input, string) _match(name, input, :str, string) end def rex(name, input, regex_or_string) _match(name, input, :rex, Regexp.new(regex_or_string)) end def _quantify(parser) return nil if parser.is_a?(Symbol) && respond_to?(parser) # so that :plus and co can be overriden case parser when '?', :q, :qmark then [ 0, 1 ] when '*', :s, :star then [ 0, 0 ] when '+', :p, :plus then [ 1, 0 ] when '!' then :bang else nil end end def _narrow(parser) fail ArgumentError.new("lone quantifier #{parser}") if _quantify(parser) method(parser.to_sym) end def _parse(parser, input) #p [ caller.length, parser, input.tring ] #r = _narrow(parser).call(input) #p [ caller.length, parser, input.tring, r.to_a(children: false) ] #r _narrow(parser).call(input) end def seq(name, input, *parsers) r = ::Raabro::Tree.new(name, :seq, input) start = input.offset c = nil loop do pa = parsers.shift break unless pa if parsers.first == '!' parsers.shift c = nott(nil, input, pa) r.children << c elsif q = _quantify(parsers.first) parsers.shift c = rep(nil, input, pa, *q) r.children.concat(c.children) else c = _parse(pa, input) r.children << c end break if c.result != 1 end if c && c.result == 1 r.result = 1 r.length = input.offset - start else input.offset = start end r end def alt(name, input, *parsers) greedy = if parsers.last == true || parsers.last == false parsers.pop else false end r = ::Raabro::Tree.new(name, greedy ? :altg : :alt, input) start = input.offset c = nil parsers.each do |pa| cc = _parse(pa, input) r.children << cc input.offset = start if greedy if cc.result == 1 && cc.length >= (c ? c.length : -1) c.result = 0 if c c = cc else cc.result = 0 end else c = cc break if c.result == 1 end end if c && c.result == 1 r.result = 1 r.length = c.length input.offset = start + r.length end r.prune! if input.options[:prune] r end def altg(name, input, *parsers) alt(name, input, *parsers, true) end def rep(name, input, parser, min, max=0) min = 0 if min == nil || min < 0 max = nil if max.nil? || max < 1 r = ::Raabro::Tree.new(name, :rep, input) start = input.offset count = 0 loop do c = _parse(parser, input) r.children << c break if c.result != 1 count += 1 break if c.length < 1 break if max && count == max end if count >= min && (max == nil || count <= max) r.result = 1 r.length = input.offset - start else input.offset = start end r.prune! if input.options[:prune] r end def ren(name, input, parser) r = _parse(parser, input) r.name = name r end alias rename ren def nott(name, input, parser) start = input.offset r = ::Raabro::Tree.new(name, :nott, input) c = _parse(parser, input) r.children << c r.length = 0 r.result = c.result == 1 ? 0 : 1 input.offset = start r end def all(name, input, parser) start = input.offset length = input.string.length - input.offset r = ::Raabro::Tree.new(name, :all, input) c = _parse(parser, input) r.children << c if c.length < length input.offset = start else r.result = 1 r.length = c.length end r end def eseq(name, input, startpa, eltpa, seppa=nil, endpa=nil) jseq = false if seppa.nil? && endpa.nil? jseq = true seppa = eltpa; eltpa = startpa; startpa = nil end start = input.offset r = ::Raabro::Tree.new(name, jseq ? :jseq : :eseq, input) r.result = 1 c = nil if startpa c = _parse(startpa, input) r.children << c r.result = 0 if c.result != 1 end if r.result == 1 on_elt = false count = 0 empty_stack = 0 loop do on_elt = ! on_elt cr = _parse(on_elt ? eltpa : seppa, input) empty_stack = cr.empty? ? empty_stack + 1 : 0 cr.result = 0 if empty_stack > 1 # # prevent "no progress" r.children.push(cr) if cr.result != 1 if on_elt && count > 0 lsep = r.children[-2] lsep.result = 0 input.offset = lsep.offset end break end count += 1 end r.result = 0 if jseq && count < 1 end if r.result == 1 && endpa c = _parse(endpa, input) r.children << c r.result = 0 if c.result != 1 end if r.result == 1 r.length = input.offset - start else input.offset = start end r.prune! if input.options[:prune] r end alias jseq eseq attr_accessor :last def method_added(name) m = method(name) return unless m.arity == 1 return unless m.parameters[0][1] == :i || m.parameters[0][1] == :input @last = name.to_sym end def parse(input, opts={}) d = opts[:debug].to_i opts[:rewrite] = false if d > 0 opts[:all] = false if d > 1 opts[:prune] = false if d > 2 opts[:prune] = true unless opts.has_key?(:prune) root = self.respond_to?(:root) ? :root : @last t = if opts[:all] == false _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 end def rewrite(tree) return !! methods.find { |m| m.to_s.start_with?('rewrite_') } if tree == 0 # return true when "rewrite_xxx" methods seem to have been provided send("rewrite_#{tree.name}", tree) end def make_includable def self.included(target) target.instance_eval do extend ::Raabro::ModuleMethods extend self end end end end extend ModuleMethods make_includable # Black 0;30 Dark Gray 1;30 # Blue 0;34 Light Blue 1;34 # Green 0;32 Light Green 1;32 # Cyan 0;36 Light Cyan 1;36 # 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, 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 = (opts[:colors] || opts[:colours] || $stdout.tty?) ? [ "", "", "", "", "", "" ] : [ '', '', '', '', '', '' ] lc = tree.result == 1 ? _gn : _dg nc = tree.result == 1 ? _bl : _lg nc = lc if tree.name == nil sc = tree.result == 1 ? _yl : _dg str = if tree.children.size == 0 " #{sc}#{tree.string.length == 0 ? "#{_dg} >#{tree.nonstring(14).inspect[1..-2]}<" : tree.string.inspect}" else '' end print "#{_dg}t---\n" if depth == 0 #print "#{' ' * depth}" depth.times do |i| pipe = i % 3 == 0 ? ': ' : '| ' print i.even? ? "#{_dg}#{pipe} " : ' ' end 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, opts) } if depth == 0 print _dg print "input ln: #{tree.input.string.length}, tree ln: #{tree.length} " print "---t\n" print _rs end end end raabro-1.4.0/raabro.gemspec000066400000000000000000000015321373672633000156100ustar00rootroot00000000000000 Gem::Specification.new do |s| s.name = 'raabro' s.version = File.read( File.expand_path('../lib/raabro.rb', __FILE__) ).match(/ VERSION *= *['"]([^'"]+)/)[1] s.platform = Gem::Platform::RUBY s.authors = [ 'John Mettraux' ] s.email = [ 'jmettraux+flor@gmail.com' ] s.homepage = 'https://github.com/floraison/raabro' s.license = 'MIT' s.summary = 'a very dumb PEG parser library' s.description = %{ A very dumb PEG parser library, with a horrible interface. }.strip #s.files = `git ls-files`.split("\n") s.files = Dir[ 'README.{md,txt}', 'CHANGELOG.{md,txt}', 'CREDITS.{md,txt}', 'LICENSE.{md,txt}', 'Makefile', 'lib/**/*.rb', #'spec/**/*.rb', 'test/**/*.rb', "#{s.name}.gemspec", ] #s.add_runtime_dependency 'tzinfo' s.add_development_dependency 'rspec', '~> 3.7' s.require_path = 'lib' end raabro-1.4.0/spec/000077500000000000000000000000001373672633000137265ustar00rootroot00000000000000raabro-1.4.0/spec/all_spec.rb000066400000000000000000000022161373672633000160360ustar00rootroot00000000000000 # # specifying raabro # # Mon Sep 21 05:56:18 JST 2015 # require 'spec_helper' describe Raabro do describe '.all' do it 'fails when not all the input is consumed' do i = Raabro::Input.new('tototota') t = Raabro.all(nil, i, :to_plus) expect(t.to_a(:leaves => true)).to eq( [ nil, 0, 0, 0, nil, :all, [ [ :tos, 1, 0, 6, nil, :rep, [ [ nil, 1, 0, 2, nil, :str, 'to' ], [ nil, 1, 2, 2, nil, :str, 'to' ], [ nil, 1, 4, 2, nil, :str, 'to' ], [ nil, 0, 6, 0, nil, :str, [] ] ] ] ] ] ) expect(i.offset).to eq(0) end it 'succeeds when all the input is consumed' do i = Raabro::Input.new('tototo') t = Raabro.all(nil, i, :to_plus) expect(t.to_a(:leaves => true)).to eq( [ nil, 1, 0, 6, nil, :all, [ [ :tos, 1, 0, 6, nil, :rep, [ [ nil, 1, 0, 2, nil, :str, 'to' ], [ nil, 1, 2, 2, nil, :str, 'to' ], [ nil, 1, 4, 2, nil, :str, 'to' ], [ nil, 0, 6, 0, nil, :str, [] ] ] ] ] ] ) expect(i.offset).to eq(6) end end end raabro-1.4.0/spec/alt_spec.rb000066400000000000000000000071011373672633000160440ustar00rootroot00000000000000 # # specifying raabro # # Sun Sep 20 07:31:53 JST 2015 # require 'spec_helper' describe Raabro do describe '.alt' do it "returns a tree with result == 0 in case of failure" do i = Raabro::Input.new('tutu') t = Raabro.alt(nil, i, :ta, :to) expect(t.to_a(:leaves => true)).to eq( [ nil, 0, 0, 0, nil, :alt, [ [ nil, 0, 0, 0, nil, :str, [] ], [ nil, 0, 0, 0, nil, :str, [] ] ] ] ) expect(i.offset).to eq(0) end it "succeeds (1st alternative)" do i = Raabro::Input.new('tato') t = Raabro.alt(nil, i, :ta, :to) expect(t.to_a(:leaves => true)).to eq( [ nil, 1, 0, 2, nil, :alt, [ [ nil, 1, 0, 2, nil, :str, 'ta' ] ] ] ) expect(i.offset).to eq(2) end it "succeeds (2nd alternative)" do i = Raabro::Input.new('tato') t = Raabro.alt(nil, i, :to, :ta) expect(t.to_a(:leaves => true)).to eq( [ nil, 1, 0, 2, nil, :alt, [ [ nil, 0, 0, 0, nil, :str, [] ], [ nil, 1, 0, 2, nil, :str, 'ta' ] ] ] ) expect(i.offset).to eq(2) end it 'prunes' do i = Raabro::Input.new('tato', :prune => true) t = Raabro.alt(nil, i, :to, :ta) expect(t.to_a(:leaves => true)).to eq( [ nil, 1, 0, 2, nil, :alt, [ [ nil, 1, 0, 2, nil, :str, 'ta' ] ] ] ) expect(i.offset).to eq(2) end context 'when not greedy (default)' do it 'goes with the first successful result' do i = Raabro::Input.new('xx') t = Raabro.alt(nil, i, :onex, :twox) expect(t.to_a(:leaves => true)).to eq( [ nil, 1, 0, 1, nil, :alt, [ [ :onex, 1, 0, 1, nil, :str, 'x' ] ] ] ) expect(i.offset).to eq(1) end end context 'when greedy (last argument set to true)' do it 'takes the longest successful result' do i = Raabro::Input.new('xx') t = Raabro.alt(nil, i, :onex, :twox, true) expect(t.to_a(:leaves => true)).to eq( [ nil, 1, 0, 2, nil, :altg, [ [ :onex, 0, 0, 1, nil, :str, [] ], [ :twox, 1, 0, 2, nil, :str, 'xx' ] ] ] ) expect(i.offset).to eq(2) end end end describe '.altg' do it 'is greedy, always' do i = Raabro::Input.new('xx') t = Raabro.altg(nil, i, :onex, :twox) expect(t.to_a(:leaves => true)).to eq( [ nil, 1, 0, 2, nil, :altg, [ [ :onex, 0, 0, 1, nil, :str, [] ], [ :twox, 1, 0, 2, nil, :str, 'xx' ] ] ] ) expect(i.offset).to eq(2) end it 'prunes' do i = Raabro::Input.new('xx', :prune => true) t = Raabro.altg(nil, i, :onex, :twox) expect(t.to_a(:leaves => true)).to eq( [ nil, 1, 0, 2, nil, :altg, [ [ :twox, 1, 0, 2, nil, :str, 'xx' ] ] ] ) expect(i.offset).to eq(2) end it 'declares a single winner' do i = Raabro::Input.new('xx', :prune => true) t = Raabro.altg(nil, i, :twox, :onex) expect(t.to_a(:leaves => true)).to eq( [ nil, 1, 0, 2, nil, :altg, [ [ :twox, 1, 0, 2, nil, :str, 'xx' ] ] ] ) expect(i.offset).to eq(2) end it 'takes the longest and latest winner' do i = Raabro::Input.new('xx', :prune => true) t = Raabro.altg(nil, i, :twox, :onex, :deux) expect(t.to_a(:leaves => true)).to eq( [ nil, 1, 0, 2, nil, :altg, [ [ :deux, 1, 0, 2, nil, :str, 'xx' ] ] ] ) expect(i.offset).to eq(2) end end end raabro-1.4.0/spec/eseq_spec.rb000066400000000000000000000100551373672633000162230ustar00rootroot00000000000000 # # specifying raabro # # Mon Sep 21 10:15:35 JST 2015 # require 'spec_helper' describe Raabro do describe '.eseq' do it 'parses successfully' do i = Raabro::Input.new('') t = Raabro.eseq(:list, i, :lt, :cha, :com, :gt) expect(t.to_a(:leaves => true)).to eq( [ :list, 1, 0, 5, nil, :eseq, [ [ nil, 1, 0, 1, nil, :str, '<' ], [ nil, 1, 1, 1, nil, :rex, 'a' ], [ nil, 1, 2, 1, nil, :str, ',' ], [ nil, 1, 3, 1, nil, :rex, 'b' ], [ nil, 0, 4, 0, nil, :str, [] ], [ nil, 1, 4, 1, nil, :str, '>' ] ] ] ) expect(i.offset).to eq(5) end it 'prunes' do i = Raabro::Input.new('', :prune => true) t = Raabro.eseq(:list, i, :lt, :cha, :com, :gt) expect(t.to_a(:leaves => true)).to eq( [ :list, 1, 0, 5, nil, :eseq, [ [ nil, 1, 0, 1, nil, :str, '<' ], [ nil, 1, 1, 1, nil, :rex, 'a' ], [ nil, 1, 2, 1, nil, :str, ',' ], [ nil, 1, 3, 1, nil, :rex, 'b' ], [ nil, 1, 4, 1, nil, :str, '>' ] ] ] ) expect(i.offset).to eq(5) end it 'parses <>' do i = Raabro::Input.new('<>', :prune => true) t = Raabro.eseq(:list, i, :lt, :cha, :com, :gt) expect(t.to_a(:leaves => true)).to eq( [ :list, 1, 0, 2, nil, :eseq, [ [ nil, 1, 0, 1, nil, :str, '<' ], [ nil, 1, 1, 1, nil, :str, '>' ] ] ] ) expect(i.offset).to eq(2) end context 'no start parser' do it 'parses successfully' do i = Raabro::Input.new('a,b>', prune: false) t = Raabro.eseq(:list, i, nil, :cha, :com, :gt) expect(t.to_a(:leaves => true)).to eq( [ :list, 1, 0, 4, nil, :eseq, [ [ nil, 1, 0, 1, nil, :rex, 'a' ], [ nil, 1, 1, 1, nil, :str, ',' ], [ nil, 1, 2, 1, nil, :rex, 'b' ], [ nil, 0, 3, 0, nil, :str, [] ], [ nil, 1, 3, 1, nil, :str, '>' ] ] ] ) expect(i.offset).to eq(4) end end context 'no end parser' do it 'parses successfully' do i = Raabro::Input.new(' true)).to eq( [ :list, 1, 0, 4, nil, :eseq, [ [ nil, 1, 0, 1, nil, :str, '<' ], [ nil, 1, 1, 1, nil, :rex, 'a' ], [ nil, 1, 2, 1, nil, :str, ',' ], [ nil, 1, 3, 1, nil, :rex, 'b' ], [ nil, 0, 4, 0, nil, :str, [] ] ] ] ) expect(i.offset).to eq(4) end it 'prunes' do i = Raabro::Input.new(' true) t = Raabro.eseq(:list, i, :lt, :cha, :com, nil) expect(t.to_a(:leaves => true)).to eq( [ :list, 1, 0, 4, nil, :eseq, [ [ nil, 1, 0, 1, nil, :str, '<' ], [ nil, 1, 1, 1, nil, :rex, 'a' ], [ nil, 1, 2, 1, nil, :str, ',' ], [ nil, 1, 3, 1, nil, :rex, 'b' ] ] ] ) expect(i.offset).to eq(4) end end context 'no progress' do it 'parses <>' do i = Raabro::Input.new('<>', :prune => true) t = arr(i) expect(t.to_a(:leaves => true)).to eq( [ nil, 1, 0, 2, nil, :eseq, [ [ nil, 1, 0, 1, nil, :str, '<' ], [ nil, 1, 1, 0, nil, :rex, '' ], [ nil, 1, 1, 1, nil, :str, '>' ] ] ] ) expect(i.offset).to eq(2) end it 'parses ' do i = Raabro::Input.new('', :prune => true) t = arr(i) expect(t.to_a(:leaves => true)).to eq( [ nil, 1, 0, 6, nil, :eseq, [ [ nil, 1, 0, 1, nil, :str, '<' ], [ nil, 1, 1, 1, nil, :rex, 'a' ], [ nil, 1, 2, 1, nil, :rex, ',' ], [ nil, 1, 3, 0, nil, :rex, '' ], [ nil, 1, 3, 1, nil, :rex, ',' ], [ nil, 1, 4, 1, nil, :rex, 'a' ], [ nil, 1, 5, 1, nil, :str, '>' ] ] ] ) expect(i.offset).to eq(6) end end end end raabro-1.4.0/spec/failure_spec.rb000066400000000000000000000043411373672633000167160ustar00rootroot00000000000000 # # specifying raabro # # Thu Aug 10 07:52:29 JST 2017 # require 'spec_helper' module Sample::ToPlus include Raabro # parse def sp_star(i); rex(nil, i, /\s*/);end def to_space(i); seq(nil, i, :to, :sp_star); end def to_plus(i); rep(:tos, i, :to_space, 1); end # rewrite def rewrite(t) [ :ok, t.string ] end end module Sample::Fun include Raabro # parse # # Last function is the root, "i" stands for "input". def pa(i); rex(nil, i, /\(\s*/); end def pz(i); rex(nil, i, /\)\s*/); end def com(i); rex(nil, i, /,\s*/); end def num(i); rex(:num, i, /-?[0-9]+\s*/); end def args(i); eseq(:arg, i, :pa, :exp, :com, :pz); end def funame(i); rex(:funame, i, /[a-z][a-z0-9]*/); end def fun(i); seq(:fun, i, :funame, :args); end def exp(i); alt(:exp, i, :fun, :num); end # rewrite # # Names above (:num, :fun, ...) get a rewrite_xxx function. # "t" stands for "tree". # # The trees with a nil name are handled by rewrite_(tree) a default # rewrite function def rewrite_num(t); t.string.to_i; end def rewrite_fun(t) [ t.children[0].string ] + t.children[1].odd_children.collect { |a| rewrite(a) } end end describe 'Raabro and parse failure' do describe 'when there is a syntax error' do it 'points at the error' do t = Sample::Fun.parse('f(a, b') expect(t).to eq(nil) expect( Sample::Fun.parse('f(a, b', error: true) ).to eq( [ 1, 4, 3, 'parsing failed .../:exp/:fun/:arg', "f(a, b\n ^---" ] ) end end describe 'when not all is consumed' do it 'points at the start of the remaining input' do t = Sample::ToPlus.parse('totota') expect(t).to eq(nil) expect( Sample::ToPlus.parse('totota', error: true) ).to eq( [ 1, 5, 4, 'parsing failed, not all input was consumed', "totota\n ^---" ] ) end it 'points at the start of the remaining input (multiline)' do s = "toto\r\n ta" t = Sample::ToPlus.parse(s) expect(t).to eq(nil) expect( Sample::ToPlus.parse(s, error: true) ).to eq( [ 2, 3, 8, 'parsing failed, not all input was consumed', " ta\n ^---" ] ) end end end raabro-1.4.0/spec/jseq_spec.rb000066400000000000000000000035461373672633000162370ustar00rootroot00000000000000 # # specifying raabro # # Mon Sep 21 06:55:35 JST 2015 # require 'spec_helper' describe Raabro do describe '.jseq' do it 'parses elts joined by a separator' do i = Raabro::Input.new('a,b,c') t = Raabro.jseq(:j, i, :cha, :com) expect(t.to_a(:leaves => true)).to eq( [ :j, 1, 0, 5, nil, :jseq, [ [ nil, 1, 0, 1, nil, :rex, 'a' ], [ nil, 1, 1, 1, nil, :str, ',' ], [ nil, 1, 2, 1, nil, :rex, 'b' ], [ nil, 1, 3, 1, nil, :str, ',' ], [ nil, 1, 4, 1, nil, :rex, 'c' ], [ nil, 0, 5, 0, nil, :str, [] ] ] ] ) expect(i.offset).to eq(5) end it 'prunes' do i = Raabro::Input.new('a,b,c', :prune => true) t = Raabro.jseq(:j, i, :cha, :com) expect(t.to_a(:leaves => true)).to eq( [ :j, 1, 0, 5, nil, :jseq, [ [ nil, 1, 0, 1, nil, :rex, 'a' ], [ nil, 1, 1, 1, nil, :str, ',' ], [ nil, 1, 2, 1, nil, :rex, 'b' ], [ nil, 1, 3, 1, nil, :str, ',' ], [ nil, 1, 4, 1, nil, :rex, 'c' ] ] ] ) expect(i.offset).to eq(5) end it 'fails when 0 elements' do i = Raabro::Input.new('') t = Raabro.jseq(:j, i, :cha, :com) expect(t.to_a(:leaves => true)).to eq( [ :j, 0, 0, 0, nil, :jseq, [ [ nil, 0, 0, 0, nil, :rex, [] ] ] ] ) expect(i.offset).to eq(0) end it 'does not include trailing separators' do i = Raabro::Input.new('a,b,', :prune => false) t = Raabro.jseq(:j, i, :cha, :com) expect(t.to_a(:leaves => true)).to eq( [:j, 1, 0, 3, nil, :jseq, [ [nil, 1, 0, 1, nil, :rex, 'a'], [nil, 1, 1, 1, nil, :str, ','], [nil, 1, 2, 1, nil, :rex, 'b'], [nil, 0, 3, 1, nil, :str, []], [nil, 0, 4, 0, nil, :rex, []]]] ) end end end raabro-1.4.0/spec/nott_spec.rb000066400000000000000000000012361373672633000162530ustar00rootroot00000000000000 # # specifying raabro # # Sun May 10 13:45:35 JST 2020 # require 'spec_helper' describe Raabro do describe '.nott' do it 'hits' do i = Raabro::Input.new('to') t = Raabro.nott(:no0, i, :ta) expect(t.to_a(leaves: true)).to eq( [ :no0, 1, 0, 0, nil, :nott, [ [ nil, 0, 0, 0, nil, :str, [] ] ] ] ) expect(i.offset).to eq(0) end it 'misses' do i = Raabro::Input.new('ta') t = Raabro.nott(:no0, i, :ta) expect(t.to_a(leaves: true)).to eq( [ :no0, 0, 0, 0, nil, :nott, [ [ nil, 1, 0, 2, nil, :str, 'ta' ] ] ] ) expect(i.offset).to eq(0) end end end raabro-1.4.0/spec/ren_spec.rb000066400000000000000000000012711373672633000160520ustar00rootroot00000000000000 # # specifying raabro # # Mon Sep 21 05:46:00 JST 2015 # require 'spec_helper' describe Raabro do describe '.ren' do it 'returns the tree coming from the wrapped parser' do i = Raabro::Input.new('ta') t = Raabro.ren('renamed', i, :nta) expect(t.to_a(:leaves => true)).to eq( [ 'renamed', 1, 0, 2, nil, :str, 'ta' ] ) expect(i.offset).to eq(2) end end describe '.rename' do it 'is an alias to .ren' do i = Raabro::Input.new('ta') t = Raabro.rename('autre', i, :nta) expect(t.to_a(:leaves => true)).to eq( [ 'autre', 1, 0, 2, nil, :str, 'ta' ] ) expect(i.offset).to eq(2) end end end raabro-1.4.0/spec/rep_spec.rb000066400000000000000000000037251373672633000160620ustar00rootroot00000000000000 # # specifying raabro # # Sun Sep 20 09:36:16 JST 2015 # require 'spec_helper' describe Raabro do describe '.rep' do it 'returns a tree with result == 0 in case of failure' do i = Raabro::Input.new('toto') t = Raabro.rep(:x, i, :to, 3, 4) expect(t.to_a(:leaves => true)).to eq( [ :x, 0, 0, 0, nil, :rep, [ [ nil, 1, 0, 2, nil, :str, 'to' ], [ nil, 1, 2, 2, nil, :str, 'to' ], [ nil, 0, 4, 0, nil, :str, [] ] ] ] ) expect(i.offset).to eq(0) end it 'prunes' do i = Raabro::Input.new('toto', :prune => true) t = Raabro.rep(:x, i, :to, 3, 4) expect(t.to_a(:leaves => true)).to eq( [ :x, 0, 0, 0, nil, :rep, [ [ nil, 1, 0, 2, nil, :str, 'to' ], [ nil, 1, 2, 2, nil, :str, 'to' ] ] ] ) expect(i.offset).to eq(0) end it "fails (min not reached)" do i = Raabro::Input.new('toto') t = Raabro.rep(:x, i, :to, 3) expect(t.to_a(:leaves => true)).to eq( [ :x, 0, 0, 0, nil, :rep, [ [ nil, 1, 0, 2, nil, :str, 'to' ], [ nil, 1, 2, 2, nil, :str, 'to' ], [ nil, 0, 4, 0, nil, :str, [] ] ] ] ) expect(i.offset).to eq(0) end it "succeeds (max set)" do i = Raabro::Input.new('tototo') t = Raabro.rep(:x, i, :to, 1, 2) expect(t.to_a(:leaves => true)).to eq( [ :x, 1, 0, 4, nil, :rep, [ [ nil, 1, 0, 2, nil, :str, 'to' ], [ nil, 1, 2, 2, nil, :str, 'to' ] ] ] ) expect(i.offset).to eq(4) end it "succeeds (max not set)" do i = Raabro::Input.new('toto') t = Raabro.rep(:x, i, :to, 1) expect(t.to_a(:leaves => true)).to eq( [ :x, 1, 0, 4, nil, :rep, [ [ nil, 1, 0, 2, nil, :str, 'to' ], [ nil, 1, 2, 2, nil, :str, 'to' ], [ nil, 0, 4, 0, nil, :str, [] ] ] ] ) expect(i.offset).to eq(4) end end end raabro-1.4.0/spec/rex_spec.rb000066400000000000000000000015361373672633000160700ustar00rootroot00000000000000 # # specifying raabro # # Sun Sep 20 07:12:35 JST 2015 # require 'spec_helper' describe Raabro do describe '.rex' do it 'hits' do i = Raabro::Input.new('toto') t = Raabro.rex(nil, i, /t[ua]/) expect(t.to_a).to eq( [ nil, 0, 0, 0, nil, :rex, [] ] ) expect(i.offset).to eq(0) end it 'misses' do i = Raabro::Input.new('toto') t = Raabro.rex(nil, i, /(to)+/) expect(t.to_a(:leaves => true)).to eq( [ nil, 1, 0, 4, nil, :rex, 'toto' ] ) expect(i.offset).to eq(4) end it 'misses if the match is not at the current input offset' do i = Raabro::Input.new('tato') t = Raabro.rex(:biga, i, /(to)+/) expect(t.to_a(:leaves => true)).to eq( [ :biga, 0, 0, 0, nil, :rex, [] ] ) expect(i.offset).to eq(0) end end end raabro-1.4.0/spec/sample_spec.rb000066400000000000000000000010501373672633000165420ustar00rootroot00000000000000 # # specifying raabro # # Sun Oct 11 04:24:32 SGT 2015 # require 'spec_helper' module Sample::OwnRewrite include Raabro # parse def hello(i); str(:hello, i, 'hello'); end #alias root exp # not necessary since Raabro takes the last defined parser as the root # rewrite def rewrite(t) [ :ok, t.string ] end end describe Raabro do describe Sample::OwnRewrite do it 'uses its own rewrite' do expect( Sample::OwnRewrite.parse('hello') ).to eq( [ :ok, 'hello' ] ) end end end raabro-1.4.0/spec/sample_xel_spec.rb000066400000000000000000000047441373672633000174270ustar00rootroot00000000000000 # # specifying raabro # # Mon Sep 21 16:58:01 JST 2015 # require 'spec_helper' module Sample::Xel include Raabro # parse def pa(i); str(nil, i, '('); end def pz(i); str(nil, i, ')'); end def com(i); str(nil, i, ','); end def num(i); rex(:num, i, /-?[0-9]+/); end def args(i); eseq(:args, i, :pa, :exp, :com, :pz); end def funame(i); rex(:funame, i, /[A-Z][A-Z0-9]*/); end def fun(i); seq(:fun, i, :funame, :args); end def exp(i); alt(:exp, i, :fun, :num); end #alias root exp # not necessary since Raabro takes the last defined parser as the root # rewrite def rewrite_exp(t); rewrite(t.children[0]); end def rewrite_num(t); t.string.to_i; end def rewrite_fun(t) #[ t.children[0].string ] + #t.children[1].children.inject([]) { |a, e| a << rewrite(e) if e.name; a } [ t.children[0].string ] + t.children[1].odd_children.map { |c| rewrite(c) } end end describe Raabro do describe Sample::Xel do describe '.funame' do it 'hits' do i = Raabro::Input.new('NADA') t = Sample::Xel.funame(i) expect(t.to_a(:leaves => true)).to eq( [ :funame, 1, 0, 4, nil, :rex, 'NADA' ] ) end end describe '.fun' do it 'parses a function call' do i = Raabro::Input.new('SUM(1,MUL(4,5))', :prune => true) t = Sample::Xel.fun(i) expect(t.result).to eq(1) expect( Sample::Xel.rewrite(t) ).to eq( [ 'SUM', 1, [ 'MUL', 4, 5 ] ] ) end end describe '.parse' do it 'parses (success)' do expect( Sample::Xel.parse('MUL(7,-3)') ).to eq( [ 'MUL', 7, -3 ] ) end it 'parses (rewrite: false, success)' do expect( Sample::Xel.parse('MUL(7,-3)', rewrite: false).to_s ).to eq(%{ 1 :exp 0,9 1 :fun 0,9 1 :funame 0,3 "MUL" 1 :args 3,6 1 nil 3,1 "(" 1 :exp 4,1 1 :num 4,1 "7" 1 nil 5,1 "," 1 :exp 6,2 1 :num 6,2 "-3" 1 nil 8,1 ")" }.strip) end it 'parses (miss)' do expect(Sample::Xel.parse('MUL(7,3) ')).to eq(nil) expect(Sample::Xel.parse('MUL(7,3')).to eq(nil) end it 'parses (miss with error: true)' do expect( Sample::Xel.parse('MUL(7,3', error: true) ).to eq( [ 1, 8, 7, 'parsing failed .../:exp/:fun/:args', "MUL(7,3\n" + " ^---" ] ) end end end end raabro-1.4.0/spec/sample_xell_spec.rb000066400000000000000000000032741373672633000176000ustar00rootroot00000000000000 # # specifying raabro # # Sun Dec 13 06:10:00 JST 2015 # require 'spec_helper' module Sample::Xell include Raabro # parse def pa(i); str(nil, i, '('); end def pz(i); str(nil, i, ')'); end def com(i); str(nil, i, ','); end def num(i); rex(:num, i, /-?[0-9]+/); end def args(i); eseq(nil, i, :pa, :exp, :com, :pz); end def funame(i); rex(nil, i, /[A-Z][A-Z0-9]*/); end def fun(i); seq(:fun, i, :funame, :args); end def exp(i); alt(nil, i, :fun, :num); end # rewrite #def rewrite_(t) # # c = t.children.find { |c| c.length > 0 || c.name } # c ? rewrite(c) : nil #end # # part of aabro now def rewrite_num(t); t.string.to_i; end def rewrite_fun(t) #as = [] #t.children[1].children.each_with_index { |e, i| as << e if i.odd? } #[ t.children[0].string ] + as.collect { |a| rewrite(a) } [ t.children[0].string ] + t.children[1].odd_children.collect { |a| rewrite(a) } end end describe Raabro do describe Sample::Xell do describe '.parse' do it 'parses (success)' do expect( Sample::Xell.parse('MUL(7,-3)') ).to eq( [ 'MUL', 7, -3 ] ) end it 'parses (rewrite: false, success)' do expect( Sample::Xell.parse('MUL(7,-3)', rewrite: false).to_s ).to eq(%{ 1 nil 0,9 1 :fun 0,9 1 nil 0,3 "MUL" 1 nil 3,6 1 nil 3,1 "(" 1 nil 4,1 1 :num 4,1 "7" 1 nil 5,1 "," 1 nil 6,2 1 :num 6,2 "-3" 1 nil 8,1 ")" }.strip) end it 'parses (miss)' do expect(Sample::Xell.parse('MUL(7,3) ')).to eq(nil) expect(Sample::Xell.parse('MUL(7,3')).to eq(nil) end end end end raabro-1.4.0/spec/seq_spec.rb000066400000000000000000000213111373672633000160530ustar00rootroot00000000000000 # # specifying raabro # # Sun Sep 20 06:11:54 JST 2015 # require 'spec_helper' describe Raabro do describe '.seq' do it "returns a tree with result == 0 in case of failure" do i = Raabro::Input.new('tato') t = Raabro.seq(nil, i, :to, :ta) expect(t.to_a).to eq( [ nil, 0, 0, 0, nil, :seq, [ [ nil, 0, 0, 0, nil, :str, [] ] ] ] ) expect(i.offset).to eq(0) end it "returns a tree with result == 0 in case of failure (at 2nd step)" do i = Raabro::Input.new('tato') t = Raabro.seq(nil, i, :ta, :ta) expect( t.to_a(:leaves => true) ).to eq( [ nil, 0, 0, 0, nil, :seq, [ [ nil, 1, 0, 2, nil, :str, 'ta' ], [ nil, 0, 2, 0, nil, :str, [] ] ] ] ) expect(i.offset).to eq(0) end it "returns a tree with result == 1 in case of success" do i = Raabro::Input.new('tato') t = Raabro.seq(nil, i, :ta, :to) expect( t.to_a(:leaves => true) ).to eq( [ nil, 1, 0, 4, nil, :seq, [ [ nil, 1, 0, 2, nil, :str, 'ta' ], [ nil, 1, 2, 2, nil, :str, 'to' ] ] ] ) expect(i.offset).to eq(4) end it "names the result if there is a name" do i = Raabro::Input.new('tato') t = Raabro.seq(:x, i, :ta, :to) expect( t.to_a(:leaves => true) ).to eq( [ :x, 1, 0, 4, nil, :seq, [ [ nil, 1, 0, 2, nil, :str, 'ta' ], [ nil, 1, 2, 2, nil, :str, 'to' ] ] ] ) expect(i.offset).to eq(4) end it "names in case of failure as well" do i = Raabro::Input.new('tato') t = Raabro.seq(:y, i, :ta, :ta) expect( t.to_a(:leaves => true) ).to eq( [ :y, 0, 0, 0, nil, :seq, [ [ nil, 1, 0, 2, nil, :str, 'ta' ], [ nil, 0, 2, 0, nil, :str, [] ] ] ] ) expect(i.offset).to eq(0) end it "fails when the input string ends" do i = Raabro::Input.new('to') t = Raabro.seq(:z, i, :to, :ta) expect( t.to_a(:leaves => true) ).to eq( [ :z, 0, 0, 0, nil, :seq, [ [ nil, 1, 0, 2, nil, :str, 'to' ], [ nil, 0, 2, 0, nil, :str, [] ] ] ] ) expect(i.offset).to eq(0) end it "accepts an empty input" do i = Raabro::Input.new('tato', 4) t = Raabro.seq(nil, i, :to, :ta) expect(t.to_a).to eq( [ nil, 0, 4, 0, nil, :seq, [ [ nil, 0, 4, 0, nil, :str, [] ] ] ] ) expect(i.offset).to eq(4) end end describe 'seq and quantifiers' do describe 'a lonely quantifier' do it 'raises an ArgumentError' do i = Raabro::Input.new('tato') expect { t = Raabro.seq(nil, i, '?') }.to raise_error(ArgumentError, 'lone quantifier ?') end end describe 'the question mark quantifier' do it 'lets optional elements appear in sequences (miss)' do i = Raabro::Input.new('tato') t = Raabro.seq(nil, i, :ta, :tu, '?', :to) expect(t.to_a(:leaves => true)).to eq( [ nil, 1, 0, 4, nil, :seq, [ [ nil, 1, 0, 2, nil, :str, 'ta' ], [ nil, 0, 2, 0, nil, :str, [] ], [ nil, 1, 2, 2, nil, :str, 'to' ] ] ] ) expect(i.offset).to eq(4) end it 'lets optional elements appear in sequences (hit)' do i = Raabro::Input.new('tatuto') t = Raabro.seq(nil, i, :ta, :tu, '?', :to) expect(t.to_a(:leaves => true)).to eq( [ nil, 1, 0, 6, nil, :seq, [ [ nil, 1, 0, 2, nil, :str, 'ta' ], [ nil, 1, 2, 2, nil, :str, 'tu' ], [ nil, 1, 4, 2, nil, :str, 'to' ] ] ] ) expect(i.offset).to eq(6) end it 'lets optional elements appear in sequences (fail)' do i = Raabro::Input.new('tatututo') t = Raabro.seq(nil, i, :ta, :tu, '?', :to) expect(t.to_a(:leaves => true)).to eq( [ nil, 0, 0, 0, nil, :seq, [ [ nil, 1, 0, 2, nil, :str, 'ta' ], [ nil, 1, 2, 2, nil, :str, 'tu' ], [ nil, 0, 4, 0, nil, :str, [] ] ] ] ) expect(i.offset).to eq(0) end end describe 'the star quantifier' do it 'lets optional elements recur in sequences (hit zero)' do i = Raabro::Input.new('tato') t = Raabro.seq(nil, i, :ta, :tu, '*', :to) expect(t.to_a(:leaves => true)).to eq( [ nil, 1, 0, 4, nil, :seq, [ [ nil, 1, 0, 2, nil, :str, 'ta' ], [ nil, 0, 2, 0, nil, :str, [] ], [ nil, 1, 2, 2, nil, :str, 'to' ] ] ] ) expect(i.offset).to eq(4) end it 'lets optional elements recur in sequences (hit)' do i = Raabro::Input.new('tatututo') t = Raabro.seq(nil, i, :ta, :tu, '*', :to) expect(t.to_a(:leaves => true)).to eq( [ nil, 1, 0, 8, nil, :seq, [ [ nil, 1, 0, 2, nil, :str, 'ta' ], [ nil, 1, 2, 2, nil, :str, 'tu' ], [ nil, 1, 4, 2, nil, :str, 'tu' ], [ nil, 0, 6, 0, nil, :str, [] ], [ nil, 1, 6, 2, nil, :str, 'to' ] ] ] ) expect(i.offset).to eq(8) end it 'stops when there is no progress' do i = Raabro::Input.new('abc') t = Raabro.seq(nil, i, :to_star, '*'); expect(t.to_a(:leaves => true)).to eq( [ nil, 1, 0, 0, nil, :seq, [ [ nil, 1, 0, 0, nil, :rep, [ [ nil, 0, 0, 0, nil, :str, [] ] ] ] ] ] ) end end describe 'the plus quantifier' do it 'lets elements recur in sequences (hit)' do i = Raabro::Input.new('tatututo') t = Raabro.seq(nil, i, :ta, :tu, '+', :to) expect(t.to_a(:leaves => true)).to eq( [ nil, 1, 0, 8, nil, :seq, [ [ nil, 1, 0, 2, nil, :str, 'ta' ], [ nil, 1, 2, 2, nil, :str, 'tu' ], [ nil, 1, 4, 2, nil, :str, 'tu' ], [ nil, 0, 6, 0, nil, :str, [] ], [ nil, 1, 6, 2, nil, :str, 'to' ] ] ] ) expect(i.offset).to eq(8) end it 'lets elements recur in sequences (fail)' do i = Raabro::Input.new('tato') t = Raabro.seq(nil, i, :ta, :tu, '+', :to) expect(t.to_a(:leaves => true)).to eq( [ nil, 0, 0, 0, nil, :seq, [ [ nil, 1, 0, 2, nil, :str, 'ta' ], [ nil, 0, 2, 0, nil, :str, [] ] ] ] ) expect(i.offset).to eq(0) end it 'stops when there is no progress' do i = Raabro::Input.new('abc') t = Raabro.seq(nil, i, :to_star, '+'); expect(t.to_a(:leaves => true)).to eq( [ nil, 1, 0, 0, nil, :seq, [ [ nil, 1, 0, 0, nil, :rep, [ [ nil, 0, 0, 0, nil, :str, [] ] ] ] ] ] ) end end describe 'the exclamation mark' do it 'throws an error when lonely' do i = Raabro::Input.new('tato') expect { t = Raabro.seq(nil, i, '!') }.to raise_error(ArgumentError, 'lone quantifier !') end it 'hits post' do i = Raabro::Input.new('tatu') t = Raabro.seq(nil, i, :ta, :ta, '!') expect(t.to_a(leaves: true)).to eq( [ nil, 1, 0, 2, nil, :seq, [ [ nil, 1, 0, 2, nil, :str, 'ta' ], [ nil, 1, 2, 0, nil, :nott, [ [ nil, 0, 2, 0, nil, :str, [] ] ] ] ] ] ) expect(i.offset).to eq(2) end it 'misses post' do i = Raabro::Input.new('tata') t = Raabro.seq(nil, i, :ta, :ta, '!') expect(t.to_a(leaves: true)).to eq( [ nil, 0, 0, 0, nil, :seq, [ [ nil, 1, 0, 2, nil, :str, 'ta' ], [ nil, 0, 2, 0, nil, :nott, [ [ nil, 1, 2, 2, nil, :str, 'ta' ] ] ] ] ] ) expect(i.offset).to eq(0) end it 'hits pre' do i = Raabro::Input.new('tatu') t = Raabro.seq(nil, i, :tu, '!', :ta, :tu) expect(t.to_a(leaves: true)).to eq( [ nil, 1, 0, 4, nil, :seq, [ [ nil, 1, 0, 0, nil, :nott, [ [ nil, 0, 0, 0, nil, :str, [] ] ] ], [ nil, 1, 0, 2, nil, :str, 'ta' ], [ nil, 1, 2, 2, nil, :str, 'tu' ] ] ] ) expect(i.offset).to eq(4) end it 'misses pre' do i = Raabro::Input.new('tutu') t = Raabro.seq(nil, i, :tu, '!', :ta, :tu) expect(t.to_a(leaves: true)).to eq( [ nil, 0, 0, 0, nil, :seq, [ [ nil, 0, 0, 0, nil, :nott, [ [ nil, 1, 0, 2, nil, :str, 'tu' ] ] ] ] ] ) expect(i.offset).to eq(0) end end end end raabro-1.4.0/spec/spec_helper.rb000066400000000000000000000032131373672633000165430ustar00rootroot00000000000000 # # Specifying raabro # # Sat Sep 19 21:12:35 JST 2015 # require 'pp' require 'raabro' # # parsers def ta(i); Raabro.str(nil, i, 'ta'); end def to(i); Raabro.str(nil, i, 'to'); end def tu(i); Raabro.str(nil, i, 'tu'); end def to_plus(input); Raabro.rep(:tos, input, :to, 1); end def to_star(input); Raabro.rep(nil, input, :to, 0); end def to_qmark(input); Raabro.rep(nil, input, :to, 0, 1); end def nta(i); Raabro.str('the-ta', i, 'ta'); end def cha(i); Raabro.rex(nil, i, /\A[a-z]/); end def com(i); Raabro.str(nil, i, ','); end def chas(i); Raabro.rex(nil, i, /[a-z ]+/i); end def lt(i); Raabro.str(nil, i, '<'); end def gt(i); Raabro.str(nil, i, '>'); end def onex(i); Raabro.str(:onex, i, 'x'); end def twox(i); Raabro.str(:twox, i, 'xx'); end def deux(i); Raabro.str(:deux, i, 'xx'); end # testing eseq... def acom(i); Raabro.rex(nil, i, /,?/); end def aval(i); Raabro.rex(nil, i, /[a-z]?/); end def arr(i); Raabro.eseq(nil, i, :lt, :aval, :acom, :gt); end # # test modules module Sample; end module Sample::Cal include Raabro def sp(i); rex(nil, i, /\s+/); end def num(i); rex(:num, i, /-?[0-9]+/); end def op(i); rex(:op, i, /[+\-*\/]/); end def item(i); alt(:item, i, :num, :op); end def suite(i); jseq(nil, i, :item, :sp); end end module Sample::Arith include Raabro def number(i); rex(:number, i, /-?[0-9]+\s*/); end def plus(i); rex(:plus, i, /\+\s*/); end def minus(i); rex(:minus, i, /-\s*/); end def addition(i); seq(:addition, i, :number, :plus, :op_or_num); end def substraction(i); seq(:substraction, i, :number, :minus, :op_or_num); end def op_or_num(i); alt(nil, i, :addition, :substraction, :number); end end raabro-1.4.0/spec/str_spec.rb000066400000000000000000000025311373672633000160760ustar00rootroot00000000000000 # # specifying raabro # # Sun Sep 20 06:11:54 JST 2015 # require 'spec_helper' describe Raabro do describe '.str' do it 'returns a tree with result == 0 in case of failure' do i = Raabro::Input.new('toto') t = Raabro.str(nil, i, 'nada') expect(t.to_a).to eq( [ nil, 0, 0, 0, nil, :str, [] ] ) expect(i.offset).to eq(0) end it "returns a tree with result == 1 in case of success" do i = Raabro::Input.new('toto') t = Raabro.str(nil, i, 'toto') expect(t.to_a).to eq( [ nil, 1, 0, 4, nil, :str, [] ] ) expect(i.offset).to eq(4) end it "names the result if there is a name" do i = Raabro::Input.new('toto') t = Raabro.str(:x, i, 'toto') expect(t.to_a).to eq( [ :x, 1, 0, 4, nil, :str, [] ] ) expect(i.offset).to eq(4) end it "names in case of failure as well" do i = Raabro::Input.new('toto') t = Raabro.str(:y, i, 'nada') expect(t.to_a).to eq( [ :y, 0, 0, 0, nil, :str, [] ] ) expect(i.offset).to eq(0) end it "accepts an empty input" do i = Raabro::Input.new('toto') i.offset = 4 t = Raabro.str(nil, i, 'nada') expect(t.to_a).to eq( [ nil, 0, 4, 0, nil, :str, [] ] ) expect(i.offset).to eq(4) end end end raabro-1.4.0/spec/tree_spec.rb000066400000000000000000000106621373672633000162310ustar00rootroot00000000000000 # # specifying raabro # # Tue Sep 22 07:55:52 JST 2015 # require 'spec_helper' describe Raabro::Tree do describe '.lookup' do it 'returns the first node with the given name' do t = Sample::Cal.parse('4 5 6 + 1 2 3 * +', rewrite: false) expect( t.lookup('item').to_a(:leaves) ).to eq( [ :item, 1, 0, 1, nil, :alt, [ [ :num, 1, 0, 1, nil, :rex, '4' ] ] ] ) end it 'returns the first named node if the given name is nil' do t = Sample::Cal.parse('4 5 6 + 1 2 3 * +', rewrite: false) expect( t.lookup.to_a(:leaves) ).to eq( [ :item, 1, 0, 1, nil, :alt, [ [ :num, 1, 0, 1, nil, :rex, '4' ] ] ] ) end end describe '.sublookup' do it 'skips the callee node' do t = Sample::Cal.parse('4 5 6 + 1 2 3 * +', rewrite: false) t = t.children[0] expect( t.sublookup.to_a(:leaves) ).to eq( [ :num, 1, 0, 1, nil, :rex, '4' ] ) end end describe '.gather' do it 'returns all the nodes with a given name' do t = Sample::Cal.parse('4 5 6 + 1 2 3 * +', rewrite: false) expect( t.gather('op').collect { |n| n.to_a(:leaves) } ).to eq( [ [ :op, 1, 6, 1, nil, :rex, '+' ], [ :op, 1, 14, 1, nil, :rex, '*' ], [ :op, 1, 16, 1, nil, :rex, '+' ] ] ) end it 'returns all the nodes with a name if the given name is nil' do t = Sample::Cal.parse('4 5 6 + 1 2 3 * +', rewrite: false) expect( t.gather.collect { |n| n.to_a(:leaves) } ).to eq([ [ :item, 1, 0, 1, nil, :alt, [ [ :num, 1, 0, 1, nil, :rex, '4' ] ] ], [ :item, 1, 2, 1, nil, :alt, [ [ :num, 1, 2, 1, nil, :rex, '5' ] ] ], [ :item, 1, 4, 1, nil, :alt, [ [ :num, 1, 4, 1, nil, :rex, '6' ] ] ], [ :item, 1, 6, 1, nil, :alt, [ [ :op, 1, 6, 1, nil, :rex, '+' ] ] ], [ :item, 1, 8, 1, nil, :alt, [ [ :num, 1, 8, 1, nil, :rex, '1' ] ] ], [ :item, 1, 10, 1, nil, :alt, [ [ :num, 1, 10, 1, nil, :rex, '2' ] ] ], [ :item, 1, 12, 1, nil, :alt, [ [ :num, 1, 12, 1, nil, :rex, '3' ] ] ], [ :item, 1, 14, 1, nil, :alt, [ [ :op, 1, 14, 1, nil, :rex, '*' ] ] ], [ :item, 1, 16, 1, nil, :alt, [ [ :op, 1, 16, 1, nil, :rex, '+' ] ] ] ]) end end describe '.subgather' do it 'skips the callee node' do t = Sample::Cal.parse('4 5 6 + 1 2 3 * +', rewrite: false) expect( t.children[0].subgather.collect { |n| n.to_a(:leaves) } ).to eq([ [ :num, 1, 0, 1, nil, :rex, '4' ] ]) end end describe '.string' do it 'returns the string covered by the tree' do t = Sample::Arith.parse('11 + 12', rewrite: false) #Raabro.pp(t, colours: true) expect(t.string).to eq('11 + 12') expect(t.sublookup(:number).string).to eq('11 ') expect(t.sublookup(:plus).string).to eq('+ ') end end describe '.strinp' do it 'returns the string covered by the tree by stripped' do t = Sample::Arith.parse('11 + 13', rewrite: false) #Raabro.pp(t, colours: true) expect(t.strinp).to eq('11 + 13') expect(t.sublookup(:number).strinp).to eq('11') expect(t.sublookup(:plus).strinp).to eq('+') end end describe '.strim' do it 'returns the string covered by the tree by stripped' do t = Sample::Arith.parse('11 + 13', rewrite: false) #Raabro.pp(t, colours: true) expect(t.strim).to eq('11 + 13') expect(t.sublookup(:number).strim).to eq('11') expect(t.sublookup(:plus).strim).to eq('+') end end describe '.strind' do it 'returns the string covered by the tree downcased' do i = Raabro::Input.new('Hello') t = chas(i) expect(t.strind).to eq('hello') end end describe '.strinpd' do it 'returns the string covered by the tree stripped and downcased' do i = Raabro::Input.new('AloaH ') t = chas(i) expect(t.strinpd).to eq('aloah') end end describe '.symbol' do it 'returns the string covered by the tree as a symbol' do i = Raabro::Input.new('Hello ') t = chas(i) expect(t.symbol).to eq(:Hello) end end describe '.symbod' do it 'returns the string covered by the tree as a downcased symbol' do i = Raabro::Input.new('Hello ') t = chas(i) expect(t.symbod).to eq(:hello) end end end