rley 0.4.03 → 0.4.04

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2d13db61565b20ef542592a59bcd056d4dd2192e
4
- data.tar.gz: a8d8c12a600d9621d6be682570cb165d526641ef
3
+ metadata.gz: 5100723b47c2572c2ac0b5996413eb4cd8e462ba
4
+ data.tar.gz: 4d37be9ca7128a36f77505560c7214454e413eb5
5
5
  SHA512:
6
- metadata.gz: 679e3f7d6747264092f317521e1f8f9e241ad912de71280c0c6d68454110bd3ba75fdc6f1f4a9c76ac61622ed87fba86f2662e3f15b5cd9a0e2d571b340e2988
7
- data.tar.gz: edb83ffb5fb673f27abef6c7ef10014fb8c6c312de093251f6ce509e2893c20cf5114cb77abf1b97c1406d9d22d474b0ab577829acb9d59f58117e43e96eaef2
6
+ metadata.gz: c197b1b962408e3a3ce4be5d310c227bdc638028d9a40d26b89c544232f59a8ce994228e4ae3673cbe6147dbcd520ee53c36a0620e3c7871edd3aba46762933f
7
+ data.tar.gz: 21b59e0b9b5c942be83954b35ee15650e1bc2c2aa2f9a6f1ebba645b94e3f822df510026825354512cf7eea879431feed852f34cef9fd176c5d0b89377504a46
@@ -1,8 +1,15 @@
1
+ ### 0.4.04 / 2017-05-01
2
+ * [NEW] `Asciitree` formatter class. Allows parse tree output in simple printable text.
3
+ * [CHANGE] Major enhancements in directory `examples\data_formats\JSON`. The demo command-line tool parses JSON and outputs the parse tree in one of the supported formats.
4
+
1
5
  ### 0.4.03 / 2017-04-17
2
6
  * [FIX] File `rley.rb` reference to obsolete `EarleyParser` class removed.
3
7
  * [NEW] `BracketNotation` formatter class. Allows parse tree output in Labelled Bracket Notation.
4
8
  * [CHANGE] Code refactoring in directory `examples\data_formats\JSON`. The demo command-line tool parses JSON and converts it into LBN (Labelled Bracket Notation). There are two diagrams (in SVG format) generated from the LBN output.
5
9
 
10
+ ### 0.4.02 / 2017-04-09
11
+ * [NEW] Module re-organization for clearer dependencies: Classes `Token` and `TokenRange` are moved to a separate module `Tokens`.
12
+ * [CHANGE] Code, specs, examples and `README.md` adapted to reflect the module re-organization.
6
13
 
7
14
  ### 0.4.01 / 2016-12-21
8
15
  * [NEW] File `appveyor.yml`. Add AppVeyor CI to Github commits. AppVeyor complements Travis by running builds under Windows OS.
@@ -1,32 +1,23 @@
1
+ require_relative 'cli_options'
1
2
  require_relative 'JSON_parser'
2
3
 
3
- # Create a JSON parser object
4
- parser = JSONParser.new
4
+ prog_name = 'JSON_demo'
5
+ prog_version = '0.1.0'
5
6
 
6
- # Parse the input file with name given in command-line
7
+ cli_options = CLIOptions.new(prog_name, prog_version, ARGV)
7
8
  if ARGV.empty?
8
- msg = <<-END_MSG
9
- A demo utility that converts a JSON file into labelled square notation (LBN).
10
- Use online tools (e.g. http://yohasebe.com/rsyntaxtree/) to visualize
11
- parse trees from LBN output.
12
-
13
- Command-line syntax:
14
-
15
- ruby #{__FILE__} filename
16
- where:
17
- filename is the name of a JSON file
18
-
19
- Example:
20
- ruby #{__FILE__} sample01.json
21
- END_MSG
22
- puts msg
9
+ puts 'Missing input file name.'
10
+ puts 'Use -h option for command-line help.'
23
11
  exit(1)
24
12
  end
13
+
25
14
  file_name = ARGV[0]
15
+ # Create a JSON parser object
16
+ parser = JSONParser.new
26
17
  result = parser.parse_file(file_name) # result object contains parse details
27
18
 
28
19
  unless result.success?
29
- # Stop if the parse failed...
20
+ # Stop if parse failed...
30
21
  puts "Parsing of '#{file_name}' failed"
31
22
  puts result.failure_reason.message
32
23
  exit(1)
@@ -34,15 +25,18 @@ end
34
25
 
35
26
  # Generate a parse tree from the parse result
36
27
  ptree = result.parse_tree
37
- require 'yaml'
38
- File.open('json1.yml', 'w') {|f| YAML.dump(ptree, f)}
28
+
29
+ # Select the output format
30
+ case cli_options[:format]
31
+ when :ascii_tree
32
+ renderer = Rley::Formatter::Asciitree.new($stdout)
33
+ when :labelled
34
+ renderer = Rley::Formatter::BracketNotation.new($stdout)
35
+ end
39
36
 
40
37
  # Let's create a parse tree visitor
41
38
  visitor = Rley::ParseTreeVisitor.new(ptree)
42
39
 
43
- # Output the labelled bracket notation of the tree
44
- use_notation = Rley::Formatter::BracketNotation.new($stdout)
45
- use_notation.render(visitor)
46
-
47
-
40
+ # Now output formatted parse tree
41
+ renderer.render(visitor)
48
42
  # End of file
@@ -4,7 +4,7 @@ require 'rley' # Load the gem
4
4
 
5
5
  ########################################
6
6
  # Define a grammar for JSON
7
- # Original JSON grammar is available http://www.json.org/fatfree.html
7
+ # Original JSON grammar is available at: http://www.json.org/fatfree.html
8
8
  # Official JSON grammar: http://rfc7159.net/rfc7159#rfc.section.2
9
9
  # Names of grammar elements are based on the RFC 7159 documentation
10
10
  builder = Rley::Syntax::GrammarBuilder.new do
@@ -27,11 +27,11 @@ builder = Rley::Syntax::GrammarBuilder.new do
27
27
  rule 'member-list' => %w(member-list value-separator member)
28
28
  rule 'member-list' => 'member'
29
29
  rule 'member' => %w(string name-separator value)
30
- rule 'array' => %w(begin-array array_items end-array)
30
+ rule 'array' => %w(begin-array array-items end-array)
31
31
  rule 'array' => %w(begin-array end-array)
32
- rule 'array_items' => %w(array_items value-separator value)
33
- rule 'array_items' => %w(value)
32
+ rule 'array-items' => %w(array-items value-separator value)
33
+ rule 'array-items' => %w(value)
34
34
  end
35
35
 
36
- # And now build the grammar...
36
+ # And now build the JSON grammar...
37
37
  GrammarJSON = builder.grammar
@@ -1,6 +1,6 @@
1
1
  # Purpose: to demonstrate how to build and render a parse tree for JSON
2
2
  # language
3
- require 'rley' # Load the gem
3
+ require 'rley' # Load the Rley gem
4
4
  require_relative 'json_lexer'
5
5
 
6
6
  # Steps to render a parse tree (of a valid parsed input):
@@ -0,0 +1,65 @@
1
+ require 'optparse'
2
+
3
+ # A Hash specialization that collects the command-line options
4
+ class CLIOptions < Hash
5
+ #labelled square notation (LBN).
6
+ #Use online tools (e.g. http://yohasebe.com/rsyntaxtree/) to visualize
7
+ #parse trees from LBN output.
8
+
9
+ def initialize(progName, progVersion, args)
10
+ super()
11
+
12
+ # Default values
13
+ self[:prog_name] = progName
14
+ self[:prog_version] = progVersion
15
+ self[:format] = :ascii_tree
16
+
17
+ options = build_option_parser
18
+ options.parse!(args)
19
+ end
20
+
21
+ private
22
+
23
+ def build_option_parser
24
+ OptionParser.new do |opts|
25
+ opts.banner = <<-END_BANNER
26
+ #{self[:prog_name]}: a demo utility that parses a JSON file
27
+ and renders its parse tree to the standard output
28
+ in the format specified in the command-line.
29
+
30
+ Usage: JSON_demo.rb [options] FILE
31
+
32
+ Examples:
33
+ JSON_demo --format ascii_tree sample01.jon
34
+ END_BANNER
35
+
36
+ opts.separator ''
37
+
38
+ format_help = <<-END_TEXT
39
+ Select the output format (default: ascii_tree). Available formats:
40
+ ascii_tree Simple text representation of parse trees
41
+ labelled Labelled square notation (LBN)
42
+ Use online tools (e.g. http://yohasebe.com/rsyntaxtree/)
43
+ to visualize parse trees from LBN output.
44
+ END_TEXT
45
+ formats = %i(ascii_tree labelled)
46
+ opts.on('-f', '--format FORMAT', formats, format_help) do |frm|
47
+ self[:format] = frm
48
+ end
49
+
50
+ opts.separator ''
51
+ opts.separator ' **** Utility ****'
52
+
53
+ opts.on('-v', '--version', 'Display the program version.') do
54
+ puts self[:prog_version]
55
+ exit
56
+ end
57
+
58
+ # No argument, shows at tail. This will print an options summary.
59
+ opts.on_tail('-h', '--help', 'Display this help message.') do
60
+ puts opts
61
+ exit
62
+ end
63
+ end
64
+ end
65
+ end # class
@@ -9,7 +9,7 @@ require_relative './rley/parser/gfg_earley_parser'
9
9
  require_relative './rley/parse_tree_visitor'
10
10
  require_relative './rley/formatter/debug'
11
11
  require_relative './rley/formatter/json'
12
- require_relative './rley/formatter/debug'
12
+ require_relative './rley/formatter/asciitree'
13
13
  require_relative './rley/formatter/bracket_notation'
14
14
 
15
15
  # End of file
@@ -3,7 +3,7 @@
3
3
 
4
4
  module Rley # Module used as a namespace
5
5
  # The version number of the gem.
6
- Version = '0.4.03'.freeze
6
+ Version = '0.4.04'.freeze
7
7
 
8
8
  # Brief description of the gem.
9
9
  Description = "Ruby implementation of the Earley's parsing algorithm".freeze
@@ -0,0 +1,128 @@
1
+ require_relative 'base_formatter'
2
+
3
+
4
+ module Rley # This module is used as a namespace
5
+ # Namespace dedicated to parse tree formatters.
6
+ module Formatter
7
+ # A formatter class that draws parse trees by using characters
8
+ class Asciitree < BaseFormatter
9
+ # TODO
10
+ attr_reader(:curr_path)
11
+
12
+ # For each node in curr_path, there is a corresponding string value.
13
+ # Allowed string values are: 'first', 'last', 'first_and_last', 'other'
14
+ attr_reader(:ranks)
15
+
16
+ attr_reader(:nesting_prefix)
17
+
18
+ attr_reader(:blank_indent)
19
+
20
+ attr_reader(:continuation_indent)
21
+
22
+ # Constructor.
23
+ # @param anIO [IO] The output stream to which the rendered grammar
24
+ # is written.
25
+ def initialize(anIO)
26
+ super(anIO)
27
+ @curr_path = []
28
+ @ranks = []
29
+
30
+ @nesting_prefix = '+-- '
31
+ @blank_indent = ' '
32
+ @continuation_indent = '| '
33
+ end
34
+
35
+
36
+ # Method called by a ParseTreeVisitor to which the formatter subscribed.
37
+ # Notification of a visit event: the visitor is about to visit
38
+ # the children of a non-terminal node
39
+ # @param _parent [NonTerminalNode]
40
+ # @param _children [Array] array of children nodes
41
+ def before_subnodes(parent, children)
42
+ rank_of(parent)
43
+ curr_path << parent
44
+ end
45
+
46
+
47
+ # Method called by a ParseTreeVisitor to which the formatter subscribed.
48
+ # Notification of a visit event: the visitor is about to visit
49
+ # a non-terminal node
50
+ # @param nonterm [NonTerminalNode]
51
+ def before_non_terminal(aNonTerm)
52
+ emit(aNonTerm)
53
+ end
54
+
55
+
56
+ # Method called by a ParseTreeVisitor to which the formatter subscribed.
57
+ # Notification of a visit event: the visitor is about to visit
58
+ # a terminal node
59
+ # @param _term [TerminalNode]
60
+ def before_terminal(aTerm)
61
+ emit(aTerm, ": '#{aTerm.token.lexeme}'")
62
+ end
63
+
64
+
65
+ # Method called by a ParseTreeVisitor to which the formatter subscribed.
66
+ # Notification of a visit event: the visitor completed the visit of
67
+ # the children of a non-terminal node.
68
+ # @param _parent [NonTerminalNode]
69
+ # @param _children [Array] array of children nodes
70
+ def after_subnodes(_parent, _children)
71
+ curr_path.pop
72
+ ranks.pop
73
+ end
74
+
75
+ private
76
+
77
+ # Parent node is last node in current path
78
+ # or current path is empty (then aChild is root node)
79
+ def rank_of(aChild)
80
+ if curr_path.empty?
81
+ rank = 'root'
82
+ elsif curr_path[-1].subnodes.size == 1
83
+ rank = 'first_and_last'
84
+ else
85
+ parent = curr_path[-1]
86
+ siblings = parent.subnodes
87
+ siblings_last_index = siblings.size - 1
88
+ rank = case siblings.find_index(aChild)
89
+ when 0 then 'first'
90
+ when siblings_last_index then 'last'
91
+ else
92
+ 'other'
93
+ end
94
+ end
95
+ self.ranks << rank
96
+ end
97
+
98
+ # 'root', 'first', 'first_and_last', 'last', 'other'
99
+ def path_prefix()
100
+ return '' if ranks.empty?
101
+
102
+ prefix = ''
103
+ @ranks.each_with_index do |rank, i|
104
+ next if i == 0
105
+
106
+ case rank
107
+ when 'first', 'other'
108
+ prefix << continuation_indent
109
+
110
+ when 'last', 'first_and_last', 'root'
111
+ prefix << blank_indent
112
+ else
113
+ end
114
+ end
115
+
116
+ prefix << nesting_prefix
117
+ return prefix
118
+ end
119
+
120
+
121
+ def emit(aNode, aSuffix = '')
122
+ output.puts("#{path_prefix}#{aNode.symbol.name}#{aSuffix}")
123
+ end
124
+ end # class
125
+ end # module
126
+ end # module
127
+
128
+ # End of file
@@ -0,0 +1,95 @@
1
+ require_relative '../../spec_helper'
2
+ require 'stringio'
3
+
4
+ require_relative '../support/grammar_abc_helper'
5
+ require_relative '../../../lib/rley/tokens/token'
6
+ require_relative '../../../lib/rley/parser/gfg_earley_parser'
7
+ require_relative '../../../lib/rley/ptree/parse_tree'
8
+ require_relative '../../../lib/rley/parse_tree_visitor'
9
+ # Load the class under test
10
+ require_relative '../../../lib/rley/formatter/asciitree'
11
+
12
+ module Rley # Re-open the module to get rid of qualified names
13
+ module Formatter
14
+ describe Asciitree do
15
+ include GrammarABCHelper # Mix-in module for grammar abc
16
+
17
+ # Factory method. Build a production with the given sequence
18
+ # of symbols as its rhs.
19
+ let(:grammar_abc) do
20
+ builder = grammar_abc_builder
21
+ builder.grammar
22
+ end
23
+
24
+ # Variables for the terminal symbols
25
+ let(:a_) { grammar_abc.name2symbol['a'] }
26
+ let(:b_) { grammar_abc.name2symbol['b'] }
27
+ let(:c_) { grammar_abc.name2symbol['c'] }
28
+
29
+ # Helper method that mimicks the output of a tokenizer
30
+ # for the language specified by gramma_abc
31
+ let(:grm_abc_tokens1) do
32
+ [
33
+ Tokens::Token.new('a', a_),
34
+ Tokens::Token.new('a', a_),
35
+ Tokens::Token.new('b', b_),
36
+ Tokens::Token.new('c', c_),
37
+ Tokens::Token.new('c', c_)
38
+ ]
39
+ end
40
+
41
+ # Factory method that builds a sample parse tree.
42
+ # Generated tree has the following structure:
43
+ # S[0,5]
44
+ # +- A[0,5]
45
+ # +- a[0,0]
46
+ # +- A[1,4]
47
+ # | +- a[1,1]
48
+ # | +- A[2,3]
49
+ # | | +- b[2,3]
50
+ # | +- c[3,4]
51
+ # +- c[4,5]
52
+ # Capital letters represent non-terminal nodes
53
+ let(:grm_abc_ptree1) do
54
+ parser = Parser::GFGEarleyParser.new(grammar_abc)
55
+ parse_result = parser.parse(grm_abc_tokens1)
56
+ parse_result.parse_tree
57
+ end
58
+
59
+ let(:destination) { StringIO.new('', 'w') }
60
+ subject { Asciitree.new(destination) }
61
+
62
+ context 'Standard creation & initialization:' do
63
+ it 'should be initialized with an IO argument' do
64
+ expect { Asciitree.new(StringIO.new('', 'w')) }.not_to raise_error
65
+ end
66
+
67
+ it 'should know its output destination' do
68
+ expect(subject.output).to eq(destination)
69
+ end
70
+ end # context
71
+
72
+
73
+ context 'Rendering:' do
74
+ it 'should render a parse tree' do
75
+ visitor = Rley::ParseTreeVisitor.new(grm_abc_ptree1)
76
+ subject.render(visitor)
77
+ expectations = <<-SNIPPET
78
+ S
79
+ +-- A
80
+ +-- a: 'a'
81
+ +-- A
82
+ | +-- a: 'a'
83
+ | +-- A
84
+ | | +-- b: 'b'
85
+ | +-- c: 'c'
86
+ +-- c: 'c'
87
+ SNIPPET
88
+ expect(destination.string).to eq(expectations)
89
+ end
90
+ end # context
91
+ end # describe
92
+ end # module
93
+ end # module
94
+
95
+ # End of file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rley
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.03
4
+ version: 0.4.04
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitri Geshef
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-17 00:00:00.000000000 Z
11
+ date: 2017-05-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -135,12 +135,14 @@ files:
135
135
  - examples/data_formats/JSON/JSON_grammar.rb
136
136
  - examples/data_formats/JSON/JSON_lexer.rb
137
137
  - examples/data_formats/JSON/JSON_parser.rb
138
+ - examples/data_formats/JSON/cli_options.rb
138
139
  - examples/general/calc/calc_demo.rb
139
140
  - examples/general/calc/calc_grammar.rb
140
141
  - examples/general/calc/calc_lexer.rb
141
142
  - examples/general/calc/calc_parser.rb
142
143
  - lib/rley.rb
143
144
  - lib/rley/constants.rb
145
+ - lib/rley/formatter/asciitree.rb
144
146
  - lib/rley/formatter/base_formatter.rb
145
147
  - lib/rley/formatter/bracket_notation.rb
146
148
  - lib/rley/formatter/debug.rb
@@ -202,6 +204,7 @@ files:
202
204
  - lib/rley/syntax/verbatim_symbol.rb
203
205
  - lib/rley/tokens/token.rb
204
206
  - lib/rley/tokens/token_range.rb
207
+ - spec/rley/formatter/asciitree_spec.rb
205
208
  - spec/rley/formatter/bracket_notation_spec.rb
206
209
  - spec/rley/formatter/debug_spec.rb
207
210
  - spec/rley/formatter/json_spec.rb
@@ -293,6 +296,7 @@ signing_key:
293
296
  specification_version: 4
294
297
  summary: Ruby implementation of the Earley's parsing algorithm
295
298
  test_files:
299
+ - spec/rley/formatter/asciitree_spec.rb
296
300
  - spec/rley/formatter/bracket_notation_spec.rb
297
301
  - spec/rley/formatter/debug_spec.rb
298
302
  - spec/rley/formatter/json_spec.rb