precedent 0.0.2
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.
- data/.gitignore +17 -0
- data/CONTRIBUTING.md +7 -0
- data/Gemfile +11 -0
- data/Guardfile +13 -0
- data/LICENSE.md +22 -0
- data/README.md +12 -0
- data/Rakefile +48 -0
- data/SYNTAX.md +142 -0
- data/bin/precedent +4 -0
- data/lib/precedent.rb +10 -0
- data/lib/precedent/cli.rb +41 -0
- data/lib/precedent/grammar/inline.rb +762 -0
- data/lib/precedent/grammar/inline.treetop +134 -0
- data/lib/precedent/grammar/node_patch.rb +12 -0
- data/lib/precedent/parser.rb +123 -0
- data/lib/precedent/translator.rb +22 -0
- data/lib/precedent/treetop_patch.rb +23 -0
- data/lib/precedent/version.rb +3 -0
- data/precedent.gemspec +40 -0
- data/spec/fixtures/long_opinion.pre +1289 -0
- data/spec/lib/precedent_spec.rb +307 -0
- data/spec/spec_helper.rb +13 -0
- metadata +251 -0
data/.gitignore
ADDED
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
1. Fork the [master branch of the respository](https://github.com/BlackacreLabs/precedent/tree/master)
|
2
|
+
2. Create a feature branch (`git checkout -b my-new-feature`).
|
3
|
+
3. Add specifications and make your changes.
|
4
|
+
4. Regenerate Treetop parsers and run specs (`rake clobber spec`).
|
5
|
+
5. Commit your changes (`git commit -am 'Add some feature'`).
|
6
|
+
6. Push to your feature branch (`git push origin my-new-feature`).
|
7
|
+
7. Send a pull request via [GitHub](https://github.com).
|
data/Gemfile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in precedent.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
group :development do
|
7
|
+
# guard-rspec does not play nice with later versions of rb-inotify
|
8
|
+
gem 'rb-inotify', '0.8.8', :require => false
|
9
|
+
gem 'rb-fsevent', :require => false
|
10
|
+
gem 'rb-fchange', :require => false
|
11
|
+
end
|
data/Guardfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
guard :bundler do
|
2
|
+
watch("precedent.gemspec")
|
3
|
+
end
|
4
|
+
|
5
|
+
require './lib/precedent/treetop_patch.rb'
|
6
|
+
guard :treetop do
|
7
|
+
watch('**/*.treetop')
|
8
|
+
end
|
9
|
+
|
10
|
+
guard :rspec, bundler: false do
|
11
|
+
watch(%r{^spec/.+_spec\.rb$})
|
12
|
+
watch(%r{^lib/(.+)\.rb$})
|
13
|
+
end
|
data/LICENSE.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# License
|
2
|
+
|
3
|
+
Copyright 2013 Blackacre Labs, a Texas non-profit corporation
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included
|
14
|
+
in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
20
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
21
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
22
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# Precedent
|
2
|
+
|
3
|
+
Lightweight markup for legal documents, inspired by the print style of
|
4
|
+
the United States Reports.
|
5
|
+
|
6
|
+
- Mixed symbolic (*, †, ‡) and numeric, non-sequential footnotes.
|
7
|
+
- Elegant control of paragraph indentation (flush or indented)
|
8
|
+
- Document-level metadata
|
9
|
+
- Elegant citation identification
|
10
|
+
- Small capitals
|
11
|
+
|
12
|
+
See `SYNTAX.md` for more details.
|
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
# Treetop grammars
|
4
|
+
|
5
|
+
GRAMMARS = FileList.new('**/*.treetop').sub('.treetop', '.rb')
|
6
|
+
|
7
|
+
desc "Generate Treetop grammars"
|
8
|
+
task :grammars => GRAMMARS
|
9
|
+
|
10
|
+
require 'rake/clean'
|
11
|
+
CLEAN.include('tmp')
|
12
|
+
CLOBBER.include(GRAMMARS)
|
13
|
+
|
14
|
+
compiler = nil
|
15
|
+
rule '.rb' => '.treetop' do |t|
|
16
|
+
unless defined? Treetop
|
17
|
+
require 'treetop'
|
18
|
+
require './lib/precedent/treetop_patch.rb'
|
19
|
+
end
|
20
|
+
compiler ||= Treetop::Compiler::GrammarCompiler.new
|
21
|
+
compiler.compile(t.source, t.name)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Performance
|
25
|
+
|
26
|
+
desc 'Profile a program run'
|
27
|
+
task :profile do
|
28
|
+
require 'ruby-prof'
|
29
|
+
require_relative 'lib/precedent.rb'
|
30
|
+
result = RubyProf.profile do
|
31
|
+
Precedent.new(File.read('spec/fixtures/long_opinion.pre')).to_hashes
|
32
|
+
end
|
33
|
+
printer = RubyProf::GraphPrinter.new(result)
|
34
|
+
printer.print(STDOUT, {})
|
35
|
+
end
|
36
|
+
|
37
|
+
# Specifications
|
38
|
+
|
39
|
+
require 'rspec/core/rake_task'
|
40
|
+
RSpec::Core::RakeTask.new(:spec => [:grammars])
|
41
|
+
|
42
|
+
# Coverage
|
43
|
+
desc 'Measure test suite code coverage'
|
44
|
+
RSpec::Core::RakeTask.new(:coverage => [:grammars]) do
|
45
|
+
ENV['COVERAGE'] = 'true'
|
46
|
+
end
|
47
|
+
|
48
|
+
task :default => :spec
|
data/SYNTAX.md
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
Precedent Syntax Guide
|
2
|
+
----------------------
|
3
|
+
|
4
|
+
## Headings, Paragraphs, Quotes, Footnotes, and Rules
|
5
|
+
|
6
|
+
Document elements can span multiple lines, but are separated by blank
|
7
|
+
(empty) lines.
|
8
|
+
|
9
|
+
### Headings
|
10
|
+
|
11
|
+
```
|
12
|
+
# A top-level heading
|
13
|
+
|
14
|
+
## A subheading
|
15
|
+
|
16
|
+
### A sub-subheading
|
17
|
+
```
|
18
|
+
|
19
|
+
### Paragraphs
|
20
|
+
|
21
|
+
The style of a paragraph is determined by the indentation of its first
|
22
|
+
line:
|
23
|
+
|
24
|
+
- 0 Spaces: Flush with the left margin (useful after block quotations)
|
25
|
+
- 2 Spaces: Indented (most paragraphs should be indented this way)
|
26
|
+
- 4 Spaces: Flush block quotation paragraphs
|
27
|
+
- 6 Spaces: Indented block quotation paragraphs
|
28
|
+
- 8 Spaces: Ragged-left (right-aligned) paragraphs
|
29
|
+
|
30
|
+
```
|
31
|
+
This first line of this paragraph will be rendered indented. It can
|
32
|
+
continue on multiple lines.
|
33
|
+
|
34
|
+
This is a flush blockquote paragraph
|
35
|
+
|
36
|
+
And this is an indented blockquote paragraph.
|
37
|
+
|
38
|
+
This paragraph follows the block quotation, and will be rendered without
|
39
|
+
indentation, i.e. flush with the left margin. This is still part of the
|
40
|
+
flush paragraph, as no blank line separates it from previous lines.
|
41
|
+
|
42
|
+
This paragraph will be set flush against the right margin, or
|
43
|
+
ragged left.
|
44
|
+
|
45
|
+
And finally, here is another standard indented paragraph.
|
46
|
+
```
|
47
|
+
|
48
|
+
### Footnotes
|
49
|
+
|
50
|
+
Footnote paragraphs are all indented paragraphs. The first paragraph in
|
51
|
+
a footnote begins with a caret (`^`) and a marker, followed by at least
|
52
|
+
one space before the text of the paragraph begins. The marker can be an
|
53
|
+
integer, asterisk (`*`), dagger (`†`), or double dagger (`‡`). That
|
54
|
+
marker should appear elsewhere within a footnote reference (discussed
|
55
|
+
below).
|
56
|
+
|
57
|
+
For example:
|
58
|
+
|
59
|
+
```
|
60
|
+
This is a body paragraph.[[12]] It has a footnote reference referring
|
61
|
+
to a footnote with the marker "12".
|
62
|
+
|
63
|
+
^12 This is the first paragraph in footnote twelve.
|
64
|
+
|
65
|
+
^ This is another paragraph in the same footnote.
|
66
|
+
```
|
67
|
+
|
68
|
+
Footnote paragraphs need not appear at the end of the document, nor must
|
69
|
+
they appear immediately after the paragraph containing the corresponding
|
70
|
+
reference. Footnotes can also appear in any order in the document.
|
71
|
+
|
72
|
+
### Horizontal Rules
|
73
|
+
|
74
|
+
Rules, written `* * *` can appear in body text or block quotations:
|
75
|
+
|
76
|
+
```
|
77
|
+
A standard paragraph.
|
78
|
+
|
79
|
+
* * *
|
80
|
+
|
81
|
+
Another standard paragraph.
|
82
|
+
|
83
|
+
A blockquote paragraph.
|
84
|
+
|
85
|
+
* * *
|
86
|
+
|
87
|
+
A flush blockquote paragrap.
|
88
|
+
|
89
|
+
A flush body paragraph.
|
90
|
+
```
|
91
|
+
|
92
|
+
## Formatting Text
|
93
|
+
|
94
|
+
Within a paragraph, the following can be used to format text:
|
95
|
+
|
96
|
+
```
|
97
|
+
This is a paragraph. The final word in this sentence is //emphasized//.
|
98
|
+
Small capitals can be set with the less-than and greater-than characters
|
99
|
+
<<like so>>. Citations can be identified with double curly brackes and
|
100
|
+
contain other formatting. {{//Id.//}} Page breaks@@2@@can be notated
|
101
|
+
with at-signs. Footnote references appear in double brackets.[[1]]
|
102
|
+
|
103
|
+
^1 The text of the footnote.
|
104
|
+
```
|
105
|
+
|
106
|
+
## Metadata
|
107
|
+
|
108
|
+
Metadata blocks permit non-content information about a document to be
|
109
|
+
embedded within it.
|
110
|
+
|
111
|
+
Metadata blocks are composed of lines containing:
|
112
|
+
|
113
|
+
- a key, composed of alphabet letters and starting with a capital letter
|
114
|
+
- a colon
|
115
|
+
- optional spaces
|
116
|
+
- content of any kind, running to the end of the line
|
117
|
+
|
118
|
+
For example:
|
119
|
+
|
120
|
+
```
|
121
|
+
Style: Sebelius v. Auburn Regional Medical Center et al.
|
122
|
+
Number: 11–1231
|
123
|
+
Argued: 2012-12-04
|
124
|
+
Decided: 2013-01-22
|
125
|
+
```
|
126
|
+
|
127
|
+
Metadata must appear at the top of a document, before any content text.
|
128
|
+
|
129
|
+
### Special Metadata Types
|
130
|
+
|
131
|
+
Content composed only of digits will be interpreted as an integer
|
132
|
+
number.
|
133
|
+
|
134
|
+
```
|
135
|
+
Opinions: 3
|
136
|
+
```
|
137
|
+
|
138
|
+
Content of the form `YYYY-MM-DD` will be interpreted as a calendar date.
|
139
|
+
|
140
|
+
```
|
141
|
+
Filed: 2013-01-01
|
142
|
+
```
|
data/bin/precedent
ADDED
data/lib/precedent.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
require_relative '../precedent'
|
4
|
+
|
5
|
+
module Precedent
|
6
|
+
class CLI < Thor
|
7
|
+
default_task :translate
|
8
|
+
|
9
|
+
option :pretty,
|
10
|
+
:aliases => '-p',
|
11
|
+
:type => :boolean,
|
12
|
+
:default => false,
|
13
|
+
:desc => "Pretty output"
|
14
|
+
|
15
|
+
OUTPUT_FORMATS = {
|
16
|
+
:json => lambda { |hashes, pretty|
|
17
|
+
require 'json'
|
18
|
+
message = pretty ? :pretty_generate : :generate
|
19
|
+
JSON.send(message, hashes)
|
20
|
+
},
|
21
|
+
:yaml => lambda { |hashes, pretty|
|
22
|
+
require 'yaml'
|
23
|
+
hashes.to_yaml
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
option :format,
|
28
|
+
:aliases => '-f',
|
29
|
+
:default => OUTPUT_FORMATS.keys.first,
|
30
|
+
:desc => "Output format: " + OUTPUT_FORMATS.keys.join('|')
|
31
|
+
|
32
|
+
desc "translate [FILE]", "Translate Precedent markup"
|
33
|
+
|
34
|
+
def translate(file=STDIN)
|
35
|
+
input = file.is_a?(String) ? File.read(file) : file.read
|
36
|
+
parsed = Precedent.new(input).to_hashes
|
37
|
+
output = OUTPUT_FORMATS[options[:format].to_sym].call(parsed, options[:pretty])
|
38
|
+
STDOUT.write(output)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,762 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# Autogenerated from a Treetop grammar. Edits may be lost.
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
module Precedent
|
7
|
+
module Inline
|
8
|
+
include Treetop::Runtime
|
9
|
+
|
10
|
+
def root
|
11
|
+
@root ||= :inline
|
12
|
+
end
|
13
|
+
|
14
|
+
module Inline0
|
15
|
+
def inline_element
|
16
|
+
elements[1]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module Inline1
|
21
|
+
def first
|
22
|
+
elements[0]
|
23
|
+
end
|
24
|
+
|
25
|
+
def subsequent
|
26
|
+
elements[1]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module Inline2
|
31
|
+
def build
|
32
|
+
elems = subsequent.elements.map(&:build).flatten
|
33
|
+
# Members of `subsequent` come in [nil, Node] lists when there
|
34
|
+
# is no preceding line break. The car values can't be ignored,
|
35
|
+
# as we need to convert newlines to spaces when they occur.
|
36
|
+
ret = elems.reduce([first.build]) do |mem, e|
|
37
|
+
last = mem.last
|
38
|
+
# Start the output list with the first element
|
39
|
+
if e.nil?
|
40
|
+
mem
|
41
|
+
# Concatenate contiguous strings
|
42
|
+
elsif last.is_a?(String) && e.is_a?(String)
|
43
|
+
mem + [mem.pop + e]
|
44
|
+
else # Hash
|
45
|
+
mem + [e]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
# If there is just one content element, give the element
|
49
|
+
# rather than a one-element list.
|
50
|
+
ret.count == 1 ? ret.first : ret
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def _nt_inline
|
55
|
+
start_index = index
|
56
|
+
if node_cache[:inline].has_key?(index)
|
57
|
+
cached = node_cache[:inline][index]
|
58
|
+
if cached
|
59
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
60
|
+
@index = cached.interval.end
|
61
|
+
end
|
62
|
+
return cached
|
63
|
+
end
|
64
|
+
|
65
|
+
i0, s0 = index, []
|
66
|
+
r1 = _nt_inline_element
|
67
|
+
s0 << r1
|
68
|
+
if r1
|
69
|
+
s2, i2 = [], index
|
70
|
+
loop do
|
71
|
+
i3, s3 = index, []
|
72
|
+
r5 = _nt_single_newline
|
73
|
+
if r5
|
74
|
+
r4 = r5
|
75
|
+
else
|
76
|
+
r4 = instantiate_node(SyntaxNode,input, index...index)
|
77
|
+
end
|
78
|
+
s3 << r4
|
79
|
+
if r4
|
80
|
+
r6 = _nt_inline_element
|
81
|
+
s3 << r6
|
82
|
+
end
|
83
|
+
if s3.last
|
84
|
+
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
|
85
|
+
r3.extend(Inline0)
|
86
|
+
else
|
87
|
+
@index = i3
|
88
|
+
r3 = nil
|
89
|
+
end
|
90
|
+
if r3
|
91
|
+
s2 << r3
|
92
|
+
else
|
93
|
+
break
|
94
|
+
end
|
95
|
+
end
|
96
|
+
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
|
97
|
+
s0 << r2
|
98
|
+
end
|
99
|
+
if s0.last
|
100
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
101
|
+
r0.extend(Inline1)
|
102
|
+
r0.extend(Inline2)
|
103
|
+
else
|
104
|
+
@index = i0
|
105
|
+
r0 = nil
|
106
|
+
end
|
107
|
+
|
108
|
+
node_cache[:inline][start_index] = r0
|
109
|
+
|
110
|
+
r0
|
111
|
+
end
|
112
|
+
|
113
|
+
def _nt_inline_element
|
114
|
+
start_index = index
|
115
|
+
if node_cache[:inline_element].has_key?(index)
|
116
|
+
cached = node_cache[:inline_element][index]
|
117
|
+
if cached
|
118
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
119
|
+
@index = cached.interval.end
|
120
|
+
end
|
121
|
+
return cached
|
122
|
+
end
|
123
|
+
|
124
|
+
i0 = index
|
125
|
+
r1 = _nt_citation
|
126
|
+
if r1
|
127
|
+
r0 = r1
|
128
|
+
else
|
129
|
+
r2 = _nt_emphasis
|
130
|
+
if r2
|
131
|
+
r0 = r2
|
132
|
+
else
|
133
|
+
r3 = _nt_smallcaps
|
134
|
+
if r3
|
135
|
+
r0 = r3
|
136
|
+
else
|
137
|
+
r4 = _nt_reference
|
138
|
+
if r4
|
139
|
+
r0 = r4
|
140
|
+
else
|
141
|
+
r5 = _nt_page_break
|
142
|
+
if r5
|
143
|
+
r0 = r5
|
144
|
+
else
|
145
|
+
r6 = _nt_space
|
146
|
+
if r6
|
147
|
+
r0 = r6
|
148
|
+
else
|
149
|
+
r7 = _nt_word
|
150
|
+
if r7
|
151
|
+
r0 = r7
|
152
|
+
else
|
153
|
+
@index = i0
|
154
|
+
r0 = nil
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
node_cache[:inline_element][start_index] = r0
|
164
|
+
|
165
|
+
r0
|
166
|
+
end
|
167
|
+
|
168
|
+
module Smallcaps0
|
169
|
+
def content
|
170
|
+
elements[1]
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
module Smallcaps1
|
176
|
+
def build
|
177
|
+
{ :type => :smallcaps,
|
178
|
+
:content => content.build }
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def _nt_smallcaps
|
183
|
+
start_index = index
|
184
|
+
if node_cache[:smallcaps].has_key?(index)
|
185
|
+
cached = node_cache[:smallcaps][index]
|
186
|
+
if cached
|
187
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
188
|
+
@index = cached.interval.end
|
189
|
+
end
|
190
|
+
return cached
|
191
|
+
end
|
192
|
+
|
193
|
+
i0, s0 = index, []
|
194
|
+
if has_terminal?('<<', false, index)
|
195
|
+
r1 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
196
|
+
@index += 2
|
197
|
+
else
|
198
|
+
terminal_parse_failure('<<')
|
199
|
+
r1 = nil
|
200
|
+
end
|
201
|
+
s0 << r1
|
202
|
+
if r1
|
203
|
+
r2 = _nt_inline
|
204
|
+
s0 << r2
|
205
|
+
if r2
|
206
|
+
if has_terminal?('>>', false, index)
|
207
|
+
r3 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
208
|
+
@index += 2
|
209
|
+
else
|
210
|
+
terminal_parse_failure('>>')
|
211
|
+
r3 = nil
|
212
|
+
end
|
213
|
+
s0 << r3
|
214
|
+
end
|
215
|
+
end
|
216
|
+
if s0.last
|
217
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
218
|
+
r0.extend(Smallcaps0)
|
219
|
+
r0.extend(Smallcaps1)
|
220
|
+
else
|
221
|
+
@index = i0
|
222
|
+
r0 = nil
|
223
|
+
end
|
224
|
+
|
225
|
+
node_cache[:smallcaps][start_index] = r0
|
226
|
+
|
227
|
+
r0
|
228
|
+
end
|
229
|
+
|
230
|
+
module Emphasis0
|
231
|
+
def content
|
232
|
+
elements[1]
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
|
237
|
+
module Emphasis1
|
238
|
+
def build
|
239
|
+
{ :type => :emphasis,
|
240
|
+
:content => content.build }
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def _nt_emphasis
|
245
|
+
start_index = index
|
246
|
+
if node_cache[:emphasis].has_key?(index)
|
247
|
+
cached = node_cache[:emphasis][index]
|
248
|
+
if cached
|
249
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
250
|
+
@index = cached.interval.end
|
251
|
+
end
|
252
|
+
return cached
|
253
|
+
end
|
254
|
+
|
255
|
+
i0, s0 = index, []
|
256
|
+
if has_terminal?('\\\\', false, index)
|
257
|
+
r1 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
258
|
+
@index += 2
|
259
|
+
else
|
260
|
+
terminal_parse_failure('\\\\')
|
261
|
+
r1 = nil
|
262
|
+
end
|
263
|
+
s0 << r1
|
264
|
+
if r1
|
265
|
+
r2 = _nt_inline
|
266
|
+
s0 << r2
|
267
|
+
if r2
|
268
|
+
if has_terminal?('\\\\', false, index)
|
269
|
+
r3 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
270
|
+
@index += 2
|
271
|
+
else
|
272
|
+
terminal_parse_failure('\\\\')
|
273
|
+
r3 = nil
|
274
|
+
end
|
275
|
+
s0 << r3
|
276
|
+
end
|
277
|
+
end
|
278
|
+
if s0.last
|
279
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
280
|
+
r0.extend(Emphasis0)
|
281
|
+
r0.extend(Emphasis1)
|
282
|
+
else
|
283
|
+
@index = i0
|
284
|
+
r0 = nil
|
285
|
+
end
|
286
|
+
|
287
|
+
node_cache[:emphasis][start_index] = r0
|
288
|
+
|
289
|
+
r0
|
290
|
+
end
|
291
|
+
|
292
|
+
module Citation0
|
293
|
+
def content
|
294
|
+
elements[1]
|
295
|
+
end
|
296
|
+
|
297
|
+
end
|
298
|
+
|
299
|
+
module Citation1
|
300
|
+
def build
|
301
|
+
{ :type => :citation,
|
302
|
+
:content => content.build }
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def _nt_citation
|
307
|
+
start_index = index
|
308
|
+
if node_cache[:citation].has_key?(index)
|
309
|
+
cached = node_cache[:citation][index]
|
310
|
+
if cached
|
311
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
312
|
+
@index = cached.interval.end
|
313
|
+
end
|
314
|
+
return cached
|
315
|
+
end
|
316
|
+
|
317
|
+
i0, s0 = index, []
|
318
|
+
if has_terminal?('{{', false, index)
|
319
|
+
r1 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
320
|
+
@index += 2
|
321
|
+
else
|
322
|
+
terminal_parse_failure('{{')
|
323
|
+
r1 = nil
|
324
|
+
end
|
325
|
+
s0 << r1
|
326
|
+
if r1
|
327
|
+
r2 = _nt_inline
|
328
|
+
s0 << r2
|
329
|
+
if r2
|
330
|
+
if has_terminal?('}}', false, index)
|
331
|
+
r3 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
332
|
+
@index += 2
|
333
|
+
else
|
334
|
+
terminal_parse_failure('}}')
|
335
|
+
r3 = nil
|
336
|
+
end
|
337
|
+
s0 << r3
|
338
|
+
end
|
339
|
+
end
|
340
|
+
if s0.last
|
341
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
342
|
+
r0.extend(Citation0)
|
343
|
+
r0.extend(Citation1)
|
344
|
+
else
|
345
|
+
@index = i0
|
346
|
+
r0 = nil
|
347
|
+
end
|
348
|
+
|
349
|
+
node_cache[:citation][start_index] = r0
|
350
|
+
|
351
|
+
r0
|
352
|
+
end
|
353
|
+
|
354
|
+
module PageBreak0
|
355
|
+
def page
|
356
|
+
elements[1]
|
357
|
+
end
|
358
|
+
|
359
|
+
end
|
360
|
+
|
361
|
+
module PageBreak1
|
362
|
+
def build
|
363
|
+
{ :type => :break,
|
364
|
+
:page => page.text_value.to_i }
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
def _nt_page_break
|
369
|
+
start_index = index
|
370
|
+
if node_cache[:page_break].has_key?(index)
|
371
|
+
cached = node_cache[:page_break][index]
|
372
|
+
if cached
|
373
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
374
|
+
@index = cached.interval.end
|
375
|
+
end
|
376
|
+
return cached
|
377
|
+
end
|
378
|
+
|
379
|
+
i0, s0 = index, []
|
380
|
+
if has_terminal?('@@', false, index)
|
381
|
+
r1 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
382
|
+
@index += 2
|
383
|
+
else
|
384
|
+
terminal_parse_failure('@@')
|
385
|
+
r1 = nil
|
386
|
+
end
|
387
|
+
s0 << r1
|
388
|
+
if r1
|
389
|
+
s2, i2 = [], index
|
390
|
+
loop do
|
391
|
+
if has_terminal?('\G[0-9]', true, index)
|
392
|
+
r3 = true
|
393
|
+
@index += 1
|
394
|
+
else
|
395
|
+
r3 = nil
|
396
|
+
end
|
397
|
+
if r3
|
398
|
+
s2 << r3
|
399
|
+
else
|
400
|
+
break
|
401
|
+
end
|
402
|
+
end
|
403
|
+
if s2.empty?
|
404
|
+
@index = i2
|
405
|
+
r2 = nil
|
406
|
+
else
|
407
|
+
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
|
408
|
+
end
|
409
|
+
s0 << r2
|
410
|
+
if r2
|
411
|
+
if has_terminal?('@@', false, index)
|
412
|
+
r4 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
413
|
+
@index += 2
|
414
|
+
else
|
415
|
+
terminal_parse_failure('@@')
|
416
|
+
r4 = nil
|
417
|
+
end
|
418
|
+
s0 << r4
|
419
|
+
end
|
420
|
+
end
|
421
|
+
if s0.last
|
422
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
423
|
+
r0.extend(PageBreak0)
|
424
|
+
r0.extend(PageBreak1)
|
425
|
+
else
|
426
|
+
@index = i0
|
427
|
+
r0 = nil
|
428
|
+
end
|
429
|
+
|
430
|
+
node_cache[:page_break][start_index] = r0
|
431
|
+
|
432
|
+
r0
|
433
|
+
end
|
434
|
+
|
435
|
+
module Reference0
|
436
|
+
def marker
|
437
|
+
elements[1]
|
438
|
+
end
|
439
|
+
|
440
|
+
end
|
441
|
+
|
442
|
+
module Reference1
|
443
|
+
def build
|
444
|
+
{ :type => :reference,
|
445
|
+
:marker => marker.text_value }
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
def _nt_reference
|
450
|
+
start_index = index
|
451
|
+
if node_cache[:reference].has_key?(index)
|
452
|
+
cached = node_cache[:reference][index]
|
453
|
+
if cached
|
454
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
455
|
+
@index = cached.interval.end
|
456
|
+
end
|
457
|
+
return cached
|
458
|
+
end
|
459
|
+
|
460
|
+
i0, s0 = index, []
|
461
|
+
if has_terminal?('[[', false, index)
|
462
|
+
r1 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
463
|
+
@index += 2
|
464
|
+
else
|
465
|
+
terminal_parse_failure('[[')
|
466
|
+
r1 = nil
|
467
|
+
end
|
468
|
+
s0 << r1
|
469
|
+
if r1
|
470
|
+
s2, i2 = [], index
|
471
|
+
loop do
|
472
|
+
if has_terminal?('\G[0-9*†‡]', true, index)
|
473
|
+
r3 = true
|
474
|
+
@index += 1
|
475
|
+
else
|
476
|
+
r3 = nil
|
477
|
+
end
|
478
|
+
if r3
|
479
|
+
s2 << r3
|
480
|
+
else
|
481
|
+
break
|
482
|
+
end
|
483
|
+
end
|
484
|
+
if s2.empty?
|
485
|
+
@index = i2
|
486
|
+
r2 = nil
|
487
|
+
else
|
488
|
+
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
|
489
|
+
end
|
490
|
+
s0 << r2
|
491
|
+
if r2
|
492
|
+
if has_terminal?(']]', false, index)
|
493
|
+
r4 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
494
|
+
@index += 2
|
495
|
+
else
|
496
|
+
terminal_parse_failure(']]')
|
497
|
+
r4 = nil
|
498
|
+
end
|
499
|
+
s0 << r4
|
500
|
+
end
|
501
|
+
end
|
502
|
+
if s0.last
|
503
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
504
|
+
r0.extend(Reference0)
|
505
|
+
r0.extend(Reference1)
|
506
|
+
else
|
507
|
+
@index = i0
|
508
|
+
r0 = nil
|
509
|
+
end
|
510
|
+
|
511
|
+
node_cache[:reference][start_index] = r0
|
512
|
+
|
513
|
+
r0
|
514
|
+
end
|
515
|
+
|
516
|
+
module SingleNewline0
|
517
|
+
def build
|
518
|
+
' '
|
519
|
+
end
|
520
|
+
end
|
521
|
+
|
522
|
+
def _nt_single_newline
|
523
|
+
start_index = index
|
524
|
+
if node_cache[:single_newline].has_key?(index)
|
525
|
+
cached = node_cache[:single_newline][index]
|
526
|
+
if cached
|
527
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
528
|
+
@index = cached.interval.end
|
529
|
+
end
|
530
|
+
return cached
|
531
|
+
end
|
532
|
+
|
533
|
+
if has_terminal?("\n", false, index)
|
534
|
+
r0 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
535
|
+
r0.extend(SingleNewline0)
|
536
|
+
@index += 1
|
537
|
+
else
|
538
|
+
terminal_parse_failure("\n")
|
539
|
+
r0 = nil
|
540
|
+
end
|
541
|
+
|
542
|
+
node_cache[:single_newline][start_index] = r0
|
543
|
+
|
544
|
+
r0
|
545
|
+
end
|
546
|
+
|
547
|
+
module Word0
|
548
|
+
def char
|
549
|
+
elements[1]
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
module Word1
|
554
|
+
def build
|
555
|
+
text_value
|
556
|
+
end
|
557
|
+
end
|
558
|
+
|
559
|
+
def _nt_word
|
560
|
+
start_index = index
|
561
|
+
if node_cache[:word].has_key?(index)
|
562
|
+
cached = node_cache[:word][index]
|
563
|
+
if cached
|
564
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
565
|
+
@index = cached.interval.end
|
566
|
+
end
|
567
|
+
return cached
|
568
|
+
end
|
569
|
+
|
570
|
+
s0, i0 = [], index
|
571
|
+
loop do
|
572
|
+
i1, s1 = index, []
|
573
|
+
i2 = index
|
574
|
+
i3 = index
|
575
|
+
if has_terminal?('{{', false, index)
|
576
|
+
r4 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
577
|
+
@index += 2
|
578
|
+
else
|
579
|
+
terminal_parse_failure('{{')
|
580
|
+
r4 = nil
|
581
|
+
end
|
582
|
+
if r4
|
583
|
+
r3 = r4
|
584
|
+
else
|
585
|
+
if has_terminal?('}}', false, index)
|
586
|
+
r5 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
587
|
+
@index += 2
|
588
|
+
else
|
589
|
+
terminal_parse_failure('}}')
|
590
|
+
r5 = nil
|
591
|
+
end
|
592
|
+
if r5
|
593
|
+
r3 = r5
|
594
|
+
else
|
595
|
+
if has_terminal?('<<', false, index)
|
596
|
+
r6 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
597
|
+
@index += 2
|
598
|
+
else
|
599
|
+
terminal_parse_failure('<<')
|
600
|
+
r6 = nil
|
601
|
+
end
|
602
|
+
if r6
|
603
|
+
r3 = r6
|
604
|
+
else
|
605
|
+
if has_terminal?('>>', false, index)
|
606
|
+
r7 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
607
|
+
@index += 2
|
608
|
+
else
|
609
|
+
terminal_parse_failure('>>')
|
610
|
+
r7 = nil
|
611
|
+
end
|
612
|
+
if r7
|
613
|
+
r3 = r7
|
614
|
+
else
|
615
|
+
if has_terminal?('[[', false, index)
|
616
|
+
r8 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
617
|
+
@index += 2
|
618
|
+
else
|
619
|
+
terminal_parse_failure('[[')
|
620
|
+
r8 = nil
|
621
|
+
end
|
622
|
+
if r8
|
623
|
+
r3 = r8
|
624
|
+
else
|
625
|
+
if has_terminal?(']]', false, index)
|
626
|
+
r9 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
627
|
+
@index += 2
|
628
|
+
else
|
629
|
+
terminal_parse_failure(']]')
|
630
|
+
r9 = nil
|
631
|
+
end
|
632
|
+
if r9
|
633
|
+
r3 = r9
|
634
|
+
else
|
635
|
+
if has_terminal?('\\\\', false, index)
|
636
|
+
r10 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
637
|
+
@index += 2
|
638
|
+
else
|
639
|
+
terminal_parse_failure('\\\\')
|
640
|
+
r10 = nil
|
641
|
+
end
|
642
|
+
if r10
|
643
|
+
r3 = r10
|
644
|
+
else
|
645
|
+
if has_terminal?('@@', false, index)
|
646
|
+
r11 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
647
|
+
@index += 2
|
648
|
+
else
|
649
|
+
terminal_parse_failure('@@')
|
650
|
+
r11 = nil
|
651
|
+
end
|
652
|
+
if r11
|
653
|
+
r3 = r11
|
654
|
+
else
|
655
|
+
@index = i3
|
656
|
+
r3 = nil
|
657
|
+
end
|
658
|
+
end
|
659
|
+
end
|
660
|
+
end
|
661
|
+
end
|
662
|
+
end
|
663
|
+
end
|
664
|
+
end
|
665
|
+
if r3
|
666
|
+
r2 = nil
|
667
|
+
else
|
668
|
+
@index = i2
|
669
|
+
r2 = instantiate_node(SyntaxNode,input, index...index)
|
670
|
+
end
|
671
|
+
s1 << r2
|
672
|
+
if r2
|
673
|
+
r12 = _nt_char
|
674
|
+
s1 << r12
|
675
|
+
end
|
676
|
+
if s1.last
|
677
|
+
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
|
678
|
+
r1.extend(Word0)
|
679
|
+
else
|
680
|
+
@index = i1
|
681
|
+
r1 = nil
|
682
|
+
end
|
683
|
+
if r1
|
684
|
+
s0 << r1
|
685
|
+
else
|
686
|
+
break
|
687
|
+
end
|
688
|
+
end
|
689
|
+
if s0.empty?
|
690
|
+
@index = i0
|
691
|
+
r0 = nil
|
692
|
+
else
|
693
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
694
|
+
r0.extend(Word1)
|
695
|
+
end
|
696
|
+
|
697
|
+
node_cache[:word][start_index] = r0
|
698
|
+
|
699
|
+
r0
|
700
|
+
end
|
701
|
+
|
702
|
+
module Space0
|
703
|
+
def build
|
704
|
+
' '
|
705
|
+
end
|
706
|
+
end
|
707
|
+
|
708
|
+
def _nt_space
|
709
|
+
start_index = index
|
710
|
+
if node_cache[:space].has_key?(index)
|
711
|
+
cached = node_cache[:space][index]
|
712
|
+
if cached
|
713
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
714
|
+
@index = cached.interval.end
|
715
|
+
end
|
716
|
+
return cached
|
717
|
+
end
|
718
|
+
|
719
|
+
if has_terminal?(' ', false, index)
|
720
|
+
r0 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
721
|
+
r0.extend(Space0)
|
722
|
+
@index += 1
|
723
|
+
else
|
724
|
+
terminal_parse_failure(' ')
|
725
|
+
r0 = nil
|
726
|
+
end
|
727
|
+
|
728
|
+
node_cache[:space][start_index] = r0
|
729
|
+
|
730
|
+
r0
|
731
|
+
end
|
732
|
+
|
733
|
+
def _nt_char
|
734
|
+
start_index = index
|
735
|
+
if node_cache[:char].has_key?(index)
|
736
|
+
cached = node_cache[:char][index]
|
737
|
+
if cached
|
738
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
739
|
+
@index = cached.interval.end
|
740
|
+
end
|
741
|
+
return cached
|
742
|
+
end
|
743
|
+
|
744
|
+
if has_terminal?('\G[\\S]', true, index)
|
745
|
+
r0 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
746
|
+
@index += 1
|
747
|
+
else
|
748
|
+
r0 = nil
|
749
|
+
end
|
750
|
+
|
751
|
+
node_cache[:char][start_index] = r0
|
752
|
+
|
753
|
+
r0
|
754
|
+
end
|
755
|
+
|
756
|
+
end
|
757
|
+
|
758
|
+
class InlineParser < Treetop::Runtime::CompiledParser
|
759
|
+
include Inline
|
760
|
+
end
|
761
|
+
|
762
|
+
end
|