grammy 0.10 → 0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/docs/TODO.md +138 -2
- data/lib/disable_ssl_verify.rb +5 -0
- data/lib/extensions/array.rb +13 -0
- data/lib/grammy/ast/transformer.rb +19 -19
- data/lib/grammy/ast.rb +8 -3
- data/lib/grammy/grammar.rb +4 -3
- data/lib/grammy/grammar.rb.bak +66 -0
- data/lib/grammy/location.rb +8 -8
- data/lib/grammy/matcher/sof.rb +1 -1
- data/lib/grammy/scanner.rb +4 -4
- data/lib/grammy/token.rb +1 -0
- data/lib/grammy/tree.rb +28 -6
- data/lib/grammy.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 62d6469d52259f78e46fdfcea47da7ac7c8a9b5b77e7cbcd3e685902c3410f98
|
|
4
|
+
data.tar.gz: 3abad7fd1e8c3fbc6f6ed6e9710c5bfb97728ef0efeadd01f15062bd1a38f971
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f301f90f661a08429f5bb956f030bc60b8950e0b108acbf7633eb2b1980d27021476602d640901c4dbc4de159bc651f0ac75bd634b6bc769c68149bf2a3e3721
|
|
7
|
+
data.tar.gz: e84cd332a524c119d615f7ba814edcd2ccabd2debe91e83f1da133cbd11b9475455d924a62a339706f050741d2a236a0dc8fc014d8cc2c8a6c8f40ca5cba3c6a
|
data/docs/TODO.md
CHANGED
|
@@ -1,5 +1,141 @@
|
|
|
1
1
|
# TODO
|
|
2
2
|
|
|
3
|
+
## IMMEDIATE (DO NOT COMMIT!) - Check these off below
|
|
4
|
+
|
|
5
|
+
- [ ] Update gem
|
|
6
|
+
- Also allow other person to use `preserves` gem name
|
|
7
|
+
|
|
8
|
+
- [ ] AI thread:
|
|
9
|
+
|
|
10
|
+
~~~markdown
|
|
11
|
+
Prompt: Allow user-defined combinators to wrap non-terminal rules
|
|
12
|
+
|
|
13
|
+
## Problem
|
|
14
|
+
|
|
15
|
+
Currently, user-defined combinators in Grammy can only wrap terminals (matchers), not rules (non-terminals).
|
|
16
|
+
|
|
17
|
+
Example that DOESN'T work:
|
|
18
|
+
```ruby
|
|
19
|
+
class MyGrammar < Grammy::Grammar
|
|
20
|
+
start :expr
|
|
21
|
+
rule(:expr) { parens(number) }
|
|
22
|
+
rule(:number) { reg(/\d+/) } # Non-terminal rule
|
|
23
|
+
|
|
24
|
+
def parens(exp) = str("(") + exp + str(")")
|
|
25
|
+
end
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
When `number` is called as a rule, it executes immediately and returns a `ParseTree`, not a `Matcher`. The sequence combinator (`+`) then fails because it can't work with ParseTrees.
|
|
29
|
+
|
|
30
|
+
Example that DOES work (using a terminal):
|
|
31
|
+
```ruby
|
|
32
|
+
class MyGrammar < Grammy::Grammar
|
|
33
|
+
start :expr
|
|
34
|
+
rule(:expr) { parens(number) }
|
|
35
|
+
terminal(:number, /\d+/) # Terminal - returns a Matcher
|
|
36
|
+
|
|
37
|
+
def parens(exp) = str("(") + exp + str(":")
|
|
38
|
+
end
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Goal
|
|
42
|
+
|
|
43
|
+
Make it possible to pass rule references (non-terminals) to user-defined combinators, so `parens(number)` works whether `number` is a terminal or a rule.
|
|
44
|
+
|
|
45
|
+
## Context
|
|
46
|
+
|
|
47
|
+
- File: `lib/grammy/grammar.rb`
|
|
48
|
+
- When a rule is called within a rule block, it should return something that can be composed with combinators
|
|
49
|
+
- The grammar DSL currently uses `instance_eval` to evaluate rule blocks
|
|
50
|
+
- Test file: `spec/grammar/user_defined_combinator_spec.rb`
|
|
51
|
+
|
|
52
|
+
## Constraints
|
|
53
|
+
|
|
54
|
+
- Don't break existing functionality with terminals
|
|
55
|
+
- Maintain the clean DSL syntax
|
|
56
|
+
- Keep the rule execution model intact for normal rule calls
|
|
57
|
+
- Should work with all combinators (`+`, `|`, `[]`, etc.)
|
|
58
|
+
|
|
59
|
+
## Test Case
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
class UserDefinedGrammar < Grammy::Grammar
|
|
63
|
+
start :us
|
|
64
|
+
rule(:us) { parens(number) }
|
|
65
|
+
rule(:number) { reg(/\d+/) } # Should work as a rule now
|
|
66
|
+
|
|
67
|
+
def parens(exp) = str("(") + exp + str(")")
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Should parse "(123)" successfully
|
|
71
|
+
```
|
|
72
|
+
~~~
|
|
73
|
+
|
|
74
|
+
- [ ] COMMIT: BUGFIX: rules are able to reference other nested rules
|
|
75
|
+
- lib/grammy/grammar.rb and tests
|
|
76
|
+
|
|
77
|
+
- [ ] Tree.each specs
|
|
78
|
+
- git fixup where I added `Enumerable`
|
|
79
|
+
- move specs to proper place
|
|
80
|
+
- commit message should mention pre-order traversal.
|
|
81
|
+
- [ ] Add AST transformation DSL
|
|
82
|
+
- I may have already tried to commit it, but missed `lib/ast*` and `spec/ast_spec.rb`
|
|
83
|
+
- Does `tree.each` traversal help?
|
|
84
|
+
- [ ] AI-assisted refactoring (suggestions, missing, etc)
|
|
85
|
+
- [x] tests
|
|
86
|
+
- [ ] code
|
|
87
|
+
- [ ] Rename Matcher to Primitive or Combinator?
|
|
88
|
+
- [ ] I suppose `custom.rb` would be the only other file in `combinators`
|
|
89
|
+
- [ ] README
|
|
90
|
+
- [ ] TODO
|
|
91
|
+
- [ ] add `Makefile` / `Rakefile` rules for common tasks (AI) (BELOW)
|
|
92
|
+
- [ ] publish to RubyGems (BELOW)
|
|
93
|
+
- [ ] check that the `CHANGELOG` is updated
|
|
94
|
+
- [ ] update version (BELOW)
|
|
95
|
+
- [ ] update dependencies (BELOW)
|
|
96
|
+
- [ ] Ruby
|
|
97
|
+
- [ ] gems
|
|
98
|
+
- [ ] RuboCop (see if any rules need updated config)
|
|
99
|
+
- [ ] bun
|
|
100
|
+
|
|
101
|
+
- [x] START ON STONE 0.10!
|
|
102
|
+
|
|
103
|
+
- [ ] CHANGELOG
|
|
104
|
+
|
|
105
|
+
- [ ] https://guides.rubygems.org/security/
|
|
106
|
+
|
|
107
|
+
- [ ] combinator aliases (BELOW)
|
|
108
|
+
- [ ] `zero_or_more`
|
|
109
|
+
- [ ] `one_or_more`
|
|
110
|
+
- [ ] `zero_or_one`, `optional` (and maybe `_opt`?)
|
|
111
|
+
- [ ] update README/TODO
|
|
112
|
+
|
|
113
|
+
- Release VERSION 0.11
|
|
114
|
+
|
|
115
|
+
- [ ] indentation (BELOW)
|
|
116
|
+
- [ ] README updates
|
|
117
|
+
- [ ] CHANGELOG
|
|
118
|
+
|
|
119
|
+
- Release VERSION 0.12
|
|
120
|
+
|
|
121
|
+
- [ ] line continuation (BELOW)
|
|
122
|
+
- [ ] README updates
|
|
123
|
+
- [ ] CHANGELOG
|
|
124
|
+
|
|
125
|
+
- Release VERSION 0.13
|
|
126
|
+
|
|
127
|
+
- [ ] error handling (BELOW)
|
|
128
|
+
- [ ] CHANGELOG
|
|
129
|
+
|
|
130
|
+
- Release VERSION 0.14
|
|
131
|
+
|
|
132
|
+
- [ ] AI prompts
|
|
133
|
+
- [ ] Copilot
|
|
134
|
+
- [ ] Claude
|
|
135
|
+
- [ ] ChatGPT
|
|
136
|
+
- [ ] easier debugging (lib/extensions/debug.rb)
|
|
137
|
+
- [ ] CHANGELOG
|
|
138
|
+
|
|
3
139
|
Here's a list of things I'd like to complete to make Grammy **great**.
|
|
4
140
|
|
|
5
141
|
## Scanner
|
|
@@ -37,7 +173,7 @@ Here's a list of things I'd like to complete to make Grammy **great**.
|
|
|
37
173
|
- [x] tree transformation DSL
|
|
38
174
|
- [ ] AST builder
|
|
39
175
|
- [ ] actions in grammar rules
|
|
40
|
-
- [
|
|
176
|
+
- [x] user-defined combinators
|
|
41
177
|
- [ ] error handling
|
|
42
178
|
- [ ] error messages
|
|
43
179
|
- [ ] error recovery
|
|
@@ -141,7 +277,7 @@ Here's a list of things I'd like to complete to make Grammy **great**.
|
|
|
141
277
|
|
|
142
278
|
- [x] publish a gem
|
|
143
279
|
- [x] `gemspec`
|
|
144
|
-
- [x]
|
|
280
|
+
- [x] publish to RubyGems
|
|
145
281
|
- [ ] CLI
|
|
146
282
|
- [ ] `bin/grammy`
|
|
147
283
|
- [ ] install with the gem
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
require "grammy/tree"
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
# The purpose of the Transformer is to provide a simpler DSL within `transform` blocks.
|
|
5
|
+
# If the `transform` is for a ParseTree, you can use `name`, `children`, and `build(child)`.
|
|
6
|
+
# If the `transform` is for a Token, you can use `name`, `token`, and `text`.
|
|
7
|
+
module Grammy
|
|
8
|
+
class AST < Tree
|
|
9
|
+
class Transformer
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
def initialize(node, node_class)
|
|
12
|
+
@node = node
|
|
13
|
+
@node_class = node_class
|
|
14
|
+
end
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
def build(child) = @node_class.build(child)
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
def name = @node.name.to_sym
|
|
19
|
+
def children = @node.children
|
|
20
|
+
def token = @node
|
|
21
|
+
def text = token.text
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/grammy/ast.rb
CHANGED
|
@@ -9,12 +9,17 @@ module Grammy
|
|
|
9
9
|
def transform(name, &blk) = transforms[name.to_sym] = blk
|
|
10
10
|
|
|
11
11
|
# The `node` will be a ParseTree or a Token. The code can handle other trees and leaves though.
|
|
12
|
+
# TODO: FIXME: Change this to use `node.each`, checking each node to see if there is a transform.
|
|
13
|
+
# ... if there isn't, we should treat the node's children as belonging to the node's parent.
|
|
12
14
|
def build(node)
|
|
13
|
-
|
|
15
|
+
node_name = node.respond_to?(:name) ? node.name.to_sym : nil
|
|
16
|
+
blk = transforms[node_name]
|
|
14
17
|
if blk
|
|
15
|
-
Transformer.new(node, self).instance_exec(&blk)
|
|
18
|
+
Grammy::AST::Transformer.new(node, self).instance_exec(&blk)
|
|
16
19
|
elsif node.respond_to?(:children)
|
|
17
|
-
|
|
20
|
+
# TODO: FIXME: We should pass the children, not ourself.
|
|
21
|
+
node.with(children: node.children.map{ build(it) })
|
|
22
|
+
# node
|
|
18
23
|
else
|
|
19
24
|
node
|
|
20
25
|
end
|
data/lib/grammy/grammar.rb
CHANGED
|
@@ -2,6 +2,7 @@ require "grammy/combinator/primitives"
|
|
|
2
2
|
require "grammy/errors"
|
|
3
3
|
require "grammy/scanner"
|
|
4
4
|
require "grammy/parse_tree"
|
|
5
|
+
require_relative "../extensions/array"
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
module Grammy
|
|
@@ -13,9 +14,9 @@ module Grammy
|
|
|
13
14
|
# DSL for defining grammar rules.
|
|
14
15
|
def start(rule_name) = @start_rule = rule_name
|
|
15
16
|
def rule(name, &)
|
|
16
|
-
rule_proc = lambda {
|
|
17
|
+
rule_proc = lambda {
|
|
17
18
|
results = instance_eval(&)
|
|
18
|
-
children = Array(results).flatten.map { |result|
|
|
19
|
+
children = Array.wrap(results).flatten.map { |result|
|
|
19
20
|
result.is_a?(Grammy::Matcher) ? result.match(@scanner) : result
|
|
20
21
|
}
|
|
21
22
|
Grammy::ParseTree.new(name.to_s, children.flatten)
|
|
@@ -59,7 +60,7 @@ module Grammy
|
|
|
59
60
|
# Primitive combinators will need access to the scanner.
|
|
60
61
|
def initialize(scanner) = @scanner = scanner
|
|
61
62
|
|
|
62
|
-
def execute_rule(rule_name) =
|
|
63
|
+
def execute_rule(rule_name) = public_send(rule_name)
|
|
63
64
|
def rules = self.class.rules
|
|
64
65
|
|
|
65
66
|
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require "grammy/combinator/primitives"
|
|
2
|
+
require "grammy/errors"
|
|
3
|
+
require "grammy/scanner"
|
|
4
|
+
require "grammy/parse_tree"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
module Grammy
|
|
8
|
+
class Grammar
|
|
9
|
+
|
|
10
|
+
include Grammy::Combinator::Primitives
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
# DSL for defining grammar rules.
|
|
14
|
+
def start(rule_name) = @start_rule = rule_name
|
|
15
|
+
def rule(name, &)
|
|
16
|
+
rule_proc = lambda {
|
|
17
|
+
results = instance_eval(&)
|
|
18
|
+
children = Array(results).flatten.map { |result|
|
|
19
|
+
result.is_a?(Grammy::Matcher) ? result.match(@scanner) : result
|
|
20
|
+
}
|
|
21
|
+
Grammy::ParseTree.new(name.to_s, children.flatten)
|
|
22
|
+
}
|
|
23
|
+
define_method(name, &rule_proc)
|
|
24
|
+
rules[name] = rule_proc
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Examples:
|
|
28
|
+
# terminal(:number, /\d+/)
|
|
29
|
+
# terminal(:number) { /\d+/ }
|
|
30
|
+
# terminal(:open_paren, "(")
|
|
31
|
+
# terminal(:open_paren) { "(" }
|
|
32
|
+
def terminal(name, pattern = nil, &block)
|
|
33
|
+
fail ArgumentError, "may only supply a pattern OR a block to #{__callee__}" if pattern && block
|
|
34
|
+
pattern ||= yield if block
|
|
35
|
+
if pattern.is_a?(Regexp)
|
|
36
|
+
terminal_proc = -> { Grammy::Matcher::Regexp.new(pattern) }
|
|
37
|
+
else
|
|
38
|
+
terminal_proc = -> { Grammy::Matcher::String.new(pattern) }
|
|
39
|
+
end
|
|
40
|
+
define_method(name, &terminal_proc)
|
|
41
|
+
rules[name] = terminal_proc
|
|
42
|
+
end
|
|
43
|
+
alias token terminal
|
|
44
|
+
|
|
45
|
+
# Access to the rules.
|
|
46
|
+
def start_rule = @start_rule || @rules.first || :start
|
|
47
|
+
def rules = @rules ||= {}
|
|
48
|
+
|
|
49
|
+
# Parse an input using the grammar.
|
|
50
|
+
def parse(input, start: start_rule)
|
|
51
|
+
scanner = Grammy::Scanner.new(input)
|
|
52
|
+
grammar = self.new(scanner)
|
|
53
|
+
result = grammar.execute_rule(start)
|
|
54
|
+
fail(Grammy::ParseError, "Parsing failed at location #{scanner.location}") if result.nil? || result.empty? && !scanner.input.empty?
|
|
55
|
+
result
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Primitive combinators will need access to the scanner.
|
|
60
|
+
def initialize(scanner) = @scanner = scanner
|
|
61
|
+
|
|
62
|
+
def execute_rule(rule_name) = send(rule_name)
|
|
63
|
+
def rules = self.class.rules
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
end
|
data/lib/grammy/location.rb
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
module Grammy
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
class Location < Data.define(:
|
|
2
|
+
# line/column are 1-based.
|
|
3
|
+
# offset is 0-based character position in the full input string.
|
|
4
|
+
class Location < Data.define(:line, :column, :offset)
|
|
5
5
|
|
|
6
|
-
def self.new(
|
|
6
|
+
def self.new(line = 1, column = 1, offset = 0)
|
|
7
7
|
super
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def advance(text)
|
|
11
11
|
newline_count = text.count("\n")
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
new_offset = offset + text.length
|
|
13
|
+
new_line = line + newline_count
|
|
14
14
|
if newline_count.zero?
|
|
15
15
|
new_column = column + text.length
|
|
16
16
|
else
|
|
17
17
|
new_column = text.length - text.rindex("\n")
|
|
18
18
|
end
|
|
19
|
-
Location.new(
|
|
19
|
+
Location.new(new_line, new_column, new_offset)
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
def to_s = "(#{
|
|
22
|
+
def to_s = "(#{line},#{column})"
|
|
23
23
|
def inspect = to_s
|
|
24
24
|
def pretty_print(pp) = pp.text inspect # For IRB output.
|
|
25
25
|
|
data/lib/grammy/matcher/sof.rb
CHANGED
|
@@ -9,7 +9,7 @@ module Grammy
|
|
|
9
9
|
def initialize = super(nil)
|
|
10
10
|
|
|
11
11
|
def match(scanner)
|
|
12
|
-
scanner.location.
|
|
12
|
+
scanner.location.offset.zero? ? Match.new(nil, scanner.location, scanner.location) : nil
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
end
|
data/lib/grammy/scanner.rb
CHANGED
|
@@ -20,7 +20,7 @@ module Grammy
|
|
|
20
20
|
# Returns `nil` if pattern does not match.
|
|
21
21
|
# Otherwise, updates @location and returns a Match object.
|
|
22
22
|
def match_string(pattern)
|
|
23
|
-
return nil if @location.
|
|
23
|
+
return nil if @location.offset >= @input.size
|
|
24
24
|
return nil unless remaining_input.start_with?(pattern)
|
|
25
25
|
match_text(pattern)
|
|
26
26
|
end
|
|
@@ -29,7 +29,7 @@ module Grammy
|
|
|
29
29
|
# Returns `nil` if pattern does not match.
|
|
30
30
|
# Otherwise, updates @location and returns a Match object.
|
|
31
31
|
def match_regexp(pattern)
|
|
32
|
-
return nil if @location.
|
|
32
|
+
return nil if @location.offset >= @input.size
|
|
33
33
|
anchored_regex = Regexp.new("\\A(?:#{pattern.source})", pattern.options)
|
|
34
34
|
match = remaining_input.match(anchored_regex)
|
|
35
35
|
return nil unless match
|
|
@@ -54,11 +54,11 @@ module Grammy
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def finished?
|
|
57
|
-
@location.
|
|
57
|
+
@location.offset == @input.size
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
private def remaining_input
|
|
61
|
-
@input[@location.
|
|
61
|
+
@input[@location.offset..]
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
# Returns matched text and its location (or nil).
|
data/lib/grammy/token.rb
CHANGED
data/lib/grammy/tree.rb
CHANGED
|
@@ -1,26 +1,48 @@
|
|
|
1
1
|
module Grammy
|
|
2
|
-
class Tree
|
|
2
|
+
class Tree
|
|
3
|
+
|
|
3
4
|
INDENTATION = 4
|
|
4
5
|
|
|
6
|
+
include Enumerable
|
|
7
|
+
|
|
8
|
+
attr_reader :name
|
|
9
|
+
attr_reader :children
|
|
10
|
+
|
|
5
11
|
# Make it easier to create nested trees.
|
|
6
|
-
def
|
|
12
|
+
def initialize(name, children = [], &block)
|
|
7
13
|
children = yield if block
|
|
8
|
-
|
|
14
|
+
@name = name
|
|
15
|
+
@children = Array(children)
|
|
9
16
|
end
|
|
10
17
|
|
|
11
|
-
def empty? =
|
|
18
|
+
def empty? = leaves.empty?
|
|
12
19
|
def leaves = children.flat_map { it.is_a?(self.class) ? it.leaves : it }.compact
|
|
13
20
|
|
|
14
21
|
def to_s(level = 0) = ([to_s_base(level)] + children.map{ to_s_child(it, level) }).join("\n")
|
|
15
22
|
|
|
16
|
-
|
|
23
|
+
# Walk the tree in pre-order, yielding every node (including self).
|
|
24
|
+
def each(&block)
|
|
25
|
+
return enum_for(:each) unless block
|
|
26
|
+
yield self
|
|
27
|
+
children.each do |child|
|
|
28
|
+
if child.respond_to?(:children) && child.respond_to?(:each)
|
|
29
|
+
child.each(&block)
|
|
30
|
+
else
|
|
31
|
+
yield child
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def inspect(level = 0) = ([inspect_base(level)] + Array(children&.map{ inspect_child(it, level) })).join("\n")
|
|
17
37
|
def to_h = {name:, children: children.map(&:to_h)}
|
|
18
38
|
def pretty_print(pp) = pp.text inspect # For IRB output.
|
|
19
39
|
|
|
20
40
|
private def to_s_base(level) = "#{indent(level)}#{name}"
|
|
21
|
-
private def inspect_base(level) = "#{indent(level)}#<#{class_name} #{name.inspect}>"
|
|
22
41
|
private def to_s_child(child, level) = child.is_a?(self.class) ? child.to_s(level + 1) : to_s_leaf(child, level + 1)
|
|
23
42
|
private def to_s_leaf(leaf, level) = "#{indent(level)}#{leaf}"
|
|
43
|
+
private def inspect_base(level) = "#{indent(level)}#<#{class_name} #{name.inspect}>"
|
|
44
|
+
private def inspect_child(child, level) = child.is_a?(self.class) ? child.inspect(level + 1) : inspect_leaf(child, level + 1)
|
|
45
|
+
private def inspect_leaf(leaf, level) = "#{indent(level)}#{leaf.inspect}"
|
|
24
46
|
private def indent(level) = " " * (level * INDENTATION)
|
|
25
47
|
private def class_name = self.class.name.split("::").last
|
|
26
48
|
|
data/lib/grammy.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: grammy
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: '0.
|
|
4
|
+
version: '0.11'
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Craig Buchek
|
|
@@ -24,6 +24,8 @@ files:
|
|
|
24
24
|
- docs/CHANGELOG.md
|
|
25
25
|
- docs/LICENSE.md
|
|
26
26
|
- docs/TODO.md
|
|
27
|
+
- lib/disable_ssl_verify.rb
|
|
28
|
+
- lib/extensions/array.rb
|
|
27
29
|
- lib/extensions/debugging.rb
|
|
28
30
|
- lib/grammy.rb
|
|
29
31
|
- lib/grammy/ast.rb
|
|
@@ -31,6 +33,7 @@ files:
|
|
|
31
33
|
- lib/grammy/combinator/primitives.rb
|
|
32
34
|
- lib/grammy/errors.rb
|
|
33
35
|
- lib/grammy/grammar.rb
|
|
36
|
+
- lib/grammy/grammar.rb.bak
|
|
34
37
|
- lib/grammy/location.rb
|
|
35
38
|
- lib/grammy/match.rb
|
|
36
39
|
- lib/grammy/matcher.rb
|
|
@@ -68,7 +71,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
68
71
|
- !ruby/object:Gem::Version
|
|
69
72
|
version: '0'
|
|
70
73
|
requirements: []
|
|
71
|
-
rubygems_version: 3.6.
|
|
74
|
+
rubygems_version: 3.6.9
|
|
72
75
|
specification_version: 4
|
|
73
76
|
summary: A PEG parsing library with a simple DSL
|
|
74
77
|
test_files: []
|