fabulator-grammar 0.0.1
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/README.markdown +73 -0
- data/Rakefile +63 -0
- data/VERSION +1 -0
- data/features/grammar.feature +88 -0
- data/features/step_definitions/expression_steps.rb +103 -0
- data/features/step_definitions/grammar_steps.rb +18 -0
- data/features/step_definitions/template_steps.rb +25 -0
- data/features/step_definitions/xml_steps.rb +23 -0
- data/features/support/env.rb +7 -0
- data/lib/fabulator/grammar.rb +16 -0
- data/lib/fabulator/grammar/actions.rb +65 -0
- data/lib/fabulator/grammar/expr/any.rb +7 -0
- data/lib/fabulator/grammar/expr/char_set.rb +45 -0
- data/lib/fabulator/grammar/expr/rule.rb +36 -0
- data/lib/fabulator/grammar/expr/rule_ref.rb +13 -0
- data/lib/fabulator/grammar/expr/rules.rb +15 -0
- data/lib/fabulator/grammar/expr/sequence.rb +26 -0
- data/lib/fabulator/grammar/expr/text.rb +11 -0
- data/lib/fabulator/grammar/parser.rb +548 -0
- data/regex.racc +183 -0
- metadata +101 -0
data/README.markdown
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
Fabulator Grammar Extension
|
2
|
+
---------------------------
|
3
|
+
|
4
|
+
This extension provides basic support for regular expressions modeled
|
5
|
+
loosely after [Perl 6 grammars][].
|
6
|
+
|
7
|
+
For now, this extension provides a single function: 'match(regex, string)'.
|
8
|
+
This function returns true or false depending on whether or not the regular
|
9
|
+
expression matches the given string.
|
10
|
+
|
11
|
+
The current implementation compiled regular expressions into Ruby
|
12
|
+
RegExp objects for faster execution. This may change as new capabilities
|
13
|
+
are added that might not be supportable by pure Ruby regular expressions.
|
14
|
+
|
15
|
+
The goal of the grammar extension is to provide a rich environment for
|
16
|
+
writing parsers that can be integrated into the Fabulator environment.
|
17
|
+
|
18
|
+
Namespace: "http://dh.tamu.edu/ns/fabulator/grammar/1.0#"
|
19
|
+
|
20
|
+
|
21
|
+
Regular Expressions
|
22
|
+
===================
|
23
|
+
|
24
|
+
The following characters are considered special and should be escaped if
|
25
|
+
you are not using for their special meaning:
|
26
|
+
|
27
|
+
Parenthesis ( )
|
28
|
+
Brackets [ ]
|
29
|
+
Curly Brackets { }
|
30
|
+
Angle Brackets < >
|
31
|
+
Dot .
|
32
|
+
Question ?
|
33
|
+
Caret ^
|
34
|
+
Dollar $
|
35
|
+
Asterisk *
|
36
|
+
Plus +
|
37
|
+
|
38
|
+
|
39
|
+
Additionally, the hyphen '-' should be the first character in a character
|
40
|
+
class if it is matching itself instead of indicated a range. It can not
|
41
|
+
be used as either the beginning or end of a range at present.
|
42
|
+
|
43
|
+
Whitespace can separate tokens in the regular expression, but the amount of
|
44
|
+
Whitespace is not significant. All tokens assume the possible existance of
|
45
|
+
whitespace in the string being matched and will not fail due to the
|
46
|
+
whitespace being there.
|
47
|
+
|
48
|
+
[Perl 6 grammars]: http://feather.perl6.nl/syn/S05.html
|
49
|
+
|
50
|
+
LICENSE:
|
51
|
+
========
|
52
|
+
|
53
|
+
Copyright (c) 2010 Texas A&M University
|
54
|
+
|
55
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
56
|
+
a copy of this software and associated documentation files (the
|
57
|
+
'Software'), to deal in the Software without restriction, including
|
58
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
59
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
60
|
+
permit persons to whom the Software is furnished to do so, subject to
|
61
|
+
the following conditions:
|
62
|
+
|
63
|
+
The above copyright notice and this permission notice shall be
|
64
|
+
included in all copies or substantial portions of the Software.
|
65
|
+
|
66
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
67
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
68
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
69
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
70
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
71
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
72
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
73
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
begin
|
2
|
+
require 'jeweler'
|
3
|
+
Jeweler::Tasks.new do |gem|
|
4
|
+
gem.name = "fabulator-grammar"
|
5
|
+
gem.summary = %Q{Grammar extension to Fabulator.}
|
6
|
+
gem.description = %Q{The grammar Fabulator extension provides regular expression support.}
|
7
|
+
gem.email = "jgsmith@tamu.edu"
|
8
|
+
gem.homepage = "http://github.com/jgsmith/ruby-fabulator-grammar"
|
9
|
+
gem.authors = ["James Smith"]
|
10
|
+
gem.add_dependency(%q<fabulator>, [">= 0.0.1"])
|
11
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
12
|
+
end
|
13
|
+
rescue LoadError
|
14
|
+
puts "Jeweler (or a dependency) not available. This is only required if you plan to package fabulator-exhibit as a gem."
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'rake'
|
18
|
+
require 'rake/rdoctask'
|
19
|
+
require 'rake/testtask'
|
20
|
+
|
21
|
+
require 'cucumber'
|
22
|
+
require 'cucumber/rake/task'
|
23
|
+
|
24
|
+
task :features => 'spec:integration'
|
25
|
+
|
26
|
+
namespace :spec do
|
27
|
+
|
28
|
+
desc "Run the Cucumber features"
|
29
|
+
Cucumber::Rake::Task.new(:integration) do |t|
|
30
|
+
t.fork = true
|
31
|
+
t.cucumber_opts = ['--format', (ENV['CUCUMBER_FORMAT'] || 'pretty')]
|
32
|
+
# t.feature_pattern = "#{extension_root}/features/**/*.feature"
|
33
|
+
t.profile = "default"
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
namespace :update do
|
39
|
+
desc "update the manifest"
|
40
|
+
task :manifest do
|
41
|
+
system %q[touch Manifest.txt; rake check_manifest | grep -v "(in " | patch]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
desc 'Generate documentation for the fabulator exhibit extension.'
|
46
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
47
|
+
rdoc.rdoc_dir = 'rdoc'
|
48
|
+
rdoc.title = 'Fabulator'
|
49
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
50
|
+
rdoc.rdoc_files.include('README')
|
51
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
52
|
+
end
|
53
|
+
|
54
|
+
# For extensions that are in transition
|
55
|
+
desc 'Test the fabulator exhibit extension.'
|
56
|
+
Rake::TestTask.new(:test) do |t|
|
57
|
+
t.libs << 'lib'
|
58
|
+
t.pattern = 'test/**/*_test.rb'
|
59
|
+
t.verbose = true
|
60
|
+
end
|
61
|
+
|
62
|
+
# Load any custom rakefiles for extension
|
63
|
+
Dir[File.dirname(__FILE__) + '/tasks/*.rake'].sort.each { |f| require f }
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,88 @@
|
|
1
|
+
Feature: Basic regex parsing
|
2
|
+
|
3
|
+
Scenario: Parsing a simple text string
|
4
|
+
Given a context
|
5
|
+
And the prefix g as "http://dh.tamu.edu/ns/fabulator/grammar/1.0#"
|
6
|
+
When I parse the regex (foo)
|
7
|
+
Then it should match "foo"
|
8
|
+
|
9
|
+
Scenario: Parsing a simple text string
|
10
|
+
Given a context
|
11
|
+
And the prefix g as "http://dh.tamu.edu/ns/fabulator/grammar/1.0#"
|
12
|
+
When I parse the regex (foo+)
|
13
|
+
Then it should match "foo"
|
14
|
+
And it should match "foooo"
|
15
|
+
And it should not match "fo"
|
16
|
+
|
17
|
+
Scenario: Parsing a simple text string
|
18
|
+
Given a context
|
19
|
+
And the prefix g as "http://dh.tamu.edu/ns/fabulator/grammar/1.0#"
|
20
|
+
When I parse the regex (foo+?)
|
21
|
+
Then it should match "fooooooo"
|
22
|
+
|
23
|
+
Scenario: Parsing a simple text string
|
24
|
+
Given a context
|
25
|
+
And the prefix g as "http://dh.tamu.edu/ns/fabulator/grammar/1.0#"
|
26
|
+
When I parse the regex (foo{1,4}$)
|
27
|
+
Then it should match "foo"
|
28
|
+
Then it should match "fooooo"
|
29
|
+
Then it should not match "foooooo"
|
30
|
+
Then it should not match "fo"
|
31
|
+
|
32
|
+
@chars
|
33
|
+
Scenario: Parsing a simple text string
|
34
|
+
Given a context
|
35
|
+
And the prefix g as "http://dh.tamu.edu/ns/fabulator/grammar/1.0#"
|
36
|
+
When I parse the regex (^[Ff]o[-a-zA-F01234-9]+?)
|
37
|
+
Then it should match "foo"
|
38
|
+
And it should match "Foo"
|
39
|
+
And it should match "FoF03z-"
|
40
|
+
And it should not match "hellofoo"
|
41
|
+
|
42
|
+
@chars
|
43
|
+
Scenario: Parsing a simple text string
|
44
|
+
Given a context
|
45
|
+
And the prefix g as "http://dh.tamu.edu/ns/fabulator/grammar/1.0#"
|
46
|
+
When I parse the regex (^[^0-9][a-z][0-9]$)
|
47
|
+
Then it should match "fo0"
|
48
|
+
And it should not match "0l0"
|
49
|
+
|
50
|
+
Scenario: Parsing a simple text string
|
51
|
+
Given a context
|
52
|
+
And the prefix g as "http://dh.tamu.edu/ns/fabulator/grammar/1.0#"
|
53
|
+
When I parse the regex (^[^0-9].[0-9]$)
|
54
|
+
Then it should match "fo0"
|
55
|
+
And it should not match "0l0"
|
56
|
+
And it should not match "00"
|
57
|
+
|
58
|
+
@chars
|
59
|
+
Scenario: Parsing a simple text string
|
60
|
+
Given a context
|
61
|
+
And the prefix g as "http://dh.tamu.edu/ns/fabulator/grammar/1.0#"
|
62
|
+
When I parse the regex ([\[-\]]o[a-z\]A-F01234-9]+?)
|
63
|
+
|
64
|
+
Scenario: Parsing a simple text string
|
65
|
+
Given a context
|
66
|
+
And the prefix g as "http://dh.tamu.edu/ns/fabulator/grammar/1.0#"
|
67
|
+
When I parse the regex (<foo><g:bar>*)
|
68
|
+
|
69
|
+
Scenario: Parsing a simple text string
|
70
|
+
Given a context
|
71
|
+
And the prefix g as "http://dh.tamu.edu/ns/fabulator/grammar/1.0#"
|
72
|
+
When I parse the regex (bar ( <foo> <g:bar> ) *)
|
73
|
+
|
74
|
+
Scenario: Adding two numbers together as a union
|
75
|
+
Given a context
|
76
|
+
And the prefix f as "http://dh.tamu.edu/ns/fabulator/1.0#"
|
77
|
+
And the prefix g as "http://dh.tamu.edu/ns/fabulator/grammar/1.0#"
|
78
|
+
When I run the expression (g:match('^foo', 'fooo'))
|
79
|
+
Then I should get 1 item
|
80
|
+
And item 0 should be true
|
81
|
+
|
82
|
+
Scenario: Adding two numbers together as a union
|
83
|
+
Given a context
|
84
|
+
And the prefix f as "http://dh.tamu.edu/ns/fabulator/1.0#"
|
85
|
+
And the prefix g as "http://dh.tamu.edu/ns/fabulator/grammar/1.0#"
|
86
|
+
When I run the expression (g:match('^foo', 'bfooo'))
|
87
|
+
Then I should get 1 item
|
88
|
+
And item 0 should be false
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
Transform /^(expression|context) \((.*)\)$/ do |n, arg|
|
4
|
+
@context ||= Fabulator::Expr::Context.new
|
5
|
+
@parser ||= Fabulator::Expr::Parser.new
|
6
|
+
@parser.parse(arg, @context)
|
7
|
+
end
|
8
|
+
|
9
|
+
Transform /^\[(.*)\]$/ do |arg|
|
10
|
+
@context ||= Fabulator::Expr::Context.new
|
11
|
+
@parser ||= Fabulator::Expr::Parser.new
|
12
|
+
@parser.parse(arg, @context)
|
13
|
+
end
|
14
|
+
|
15
|
+
Transform /^(\d+)$/ do |arg|
|
16
|
+
arg.to_i
|
17
|
+
end
|
18
|
+
|
19
|
+
Given 'a context' do
|
20
|
+
@context ||= Fabulator::Expr::Context.new
|
21
|
+
@parser ||= Fabulator::Expr::Parser.new
|
22
|
+
@grammar_parser ||= Fabulator::Grammar::Parser.new
|
23
|
+
end
|
24
|
+
|
25
|
+
Given /the prefix (\S+) as "([^"]+)"/ do |p,h|
|
26
|
+
@context ||= Fabulator::Expr::Context.new
|
27
|
+
@context.set_ns(p, h)
|
28
|
+
end
|
29
|
+
|
30
|
+
Given /that (\[.*\]) is set to (\[.*\])/ do |l,r|
|
31
|
+
@context.set_value(l, r)
|
32
|
+
end
|
33
|
+
|
34
|
+
When /I run the (expression \(.*\)) in the (context \(.*\))/ do |exp, cp|
|
35
|
+
@expr = exp
|
36
|
+
if cp.nil? || cp == ''
|
37
|
+
@result = []
|
38
|
+
@cp = @context.root
|
39
|
+
else
|
40
|
+
@cp = cp.run(@context).first || @context.root
|
41
|
+
@result = @expr.run(@context.with_root(@cp))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
When /I run the (expression \(.*\))/ do |exp|
|
46
|
+
## assume '/' as the context here
|
47
|
+
@expr = exp
|
48
|
+
@cp = @data
|
49
|
+
#puts YAML::dump(@expr)
|
50
|
+
@result = @expr.run(@context.with_root(@cp))
|
51
|
+
#puts YAML::dump(@result)
|
52
|
+
end
|
53
|
+
|
54
|
+
When /I unify the types? (.*)/ do |ts|
|
55
|
+
types = ts.split(/\s*,\s*/)
|
56
|
+
typea = types.collect { |t|
|
57
|
+
pn = t.split(/:/, 2)
|
58
|
+
[ @context.get_ns(pn[0]), pn[1] ]
|
59
|
+
}
|
60
|
+
@type_result = Fabulator::ActionLib.unify_types(
|
61
|
+
types.collect { |t|
|
62
|
+
pn = t.split(/:/, 2)
|
63
|
+
[ @context.get_ns(pn[0]), pn[1] ]
|
64
|
+
}
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
Then /I should get the type (.*)/ do |t|
|
69
|
+
pn = t.split(/:/, 2)
|
70
|
+
@type_result[0].should == @context.get_ns(pn[0])
|
71
|
+
@type_result[1].should == pn[1]
|
72
|
+
end
|
73
|
+
|
74
|
+
Then /I should get (\d+) items?/ do |count|
|
75
|
+
@result.length.should == count
|
76
|
+
end
|
77
|
+
|
78
|
+
Then /item (\d+) should be (\[.*\])/ do |i,t|
|
79
|
+
test = t.run(@context.with_root(@cp)).first
|
80
|
+
#puts "Result: #{@result[i.to_i].to_s.class.to_s}"
|
81
|
+
@result[i.to_i].to_s.should == test.to_s
|
82
|
+
end
|
83
|
+
|
84
|
+
Then /item (\d+) should be false/ do |i|
|
85
|
+
(!!@result[i.to_i].value).should == false
|
86
|
+
end
|
87
|
+
|
88
|
+
Then /item (\d+) should be true/ do |i|
|
89
|
+
(!!@result[i.to_i].value).should == true
|
90
|
+
end
|
91
|
+
|
92
|
+
Then /the (expression \(.*\)) should equal (\[.*\])/ do |x, y|
|
93
|
+
a = x.run(@context)
|
94
|
+
b = y.run(@context)
|
95
|
+
#puts YAML::dump(a)
|
96
|
+
#puts YAML::dump(b)
|
97
|
+
#puts YAML::dump(@context)
|
98
|
+
a.first.value.should == b.first.value
|
99
|
+
end
|
100
|
+
|
101
|
+
Then /the (expression \(.*\)) should be nil/ do |x|
|
102
|
+
x.run(@context).first.should == nil
|
103
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
When /^I parse the regex \((.*)\)$/ do |regex|
|
4
|
+
@context ||= Fabulator::Expr::Context.new
|
5
|
+
@grammar_parser ||= Fabulator::Grammar::Parser.new
|
6
|
+
@regex = @grammar_parser.parse(regex, @context)
|
7
|
+
# puts YAML::dump(r)
|
8
|
+
# puts @regex.to_regex
|
9
|
+
# pending # express the regexp above with the code you wish you had
|
10
|
+
end
|
11
|
+
|
12
|
+
Then /^it should match "(.*)"$/ do |str|
|
13
|
+
str.should =~ @regex.to_regex
|
14
|
+
end
|
15
|
+
|
16
|
+
Then /^it should not match "(.*)"$/ do |str|
|
17
|
+
str.should_not =~ @regex.to_regex
|
18
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
Given /^the template$/ do |doc_xml|
|
2
|
+
@template_text = doc_xml
|
3
|
+
end
|
4
|
+
|
5
|
+
When /^I render the template$/ do
|
6
|
+
parser = Fabulator::Template::Parser.new
|
7
|
+
@template_result = parser.parse(@context, @template_text)
|
8
|
+
end
|
9
|
+
|
10
|
+
When /^I set the captions to:$/ do |caption_table|
|
11
|
+
captions = { }
|
12
|
+
caption_table.hashes.each do |h|
|
13
|
+
captions[h['path']] = h['caption']
|
14
|
+
end
|
15
|
+
|
16
|
+
@template_result.add_captions(captions)
|
17
|
+
end
|
18
|
+
|
19
|
+
Then /^the rendered text should equal$/ do |doc|
|
20
|
+
@template_result.to_s.should == %{<?xml version="1.0" encoding="UTF-8"?>\n} + doc + "\n"
|
21
|
+
end
|
22
|
+
|
23
|
+
Then /^the rendered html should equal$/ do |doc|
|
24
|
+
@template_result.to_html.should == doc
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
Given /the statemachine/ do |doc_xml|
|
2
|
+
@context ||= Fabulator::Expr::Context.new
|
3
|
+
|
4
|
+
if @sm.nil?
|
5
|
+
@sm = Fabulator::Core::StateMachine.new.compile_xml(doc_xml)
|
6
|
+
else
|
7
|
+
@sm.compile_xml(doc_xml)
|
8
|
+
end
|
9
|
+
@sm.init_context(@context)
|
10
|
+
end
|
11
|
+
|
12
|
+
When /I run it with the following params:/ do |param_table|
|
13
|
+
params = { }
|
14
|
+
param_table.hashes.each do |hash|
|
15
|
+
params[hash['key']] = hash['value']
|
16
|
+
end
|
17
|
+
@sm.run(params)
|
18
|
+
#puts YAML::dump(@sm)
|
19
|
+
end
|
20
|
+
|
21
|
+
Then /it should be in the '(.*)' state/ do |s|
|
22
|
+
@sm.state.should == s
|
23
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'fabulator/grammar/parser'
|
2
|
+
require 'fabulator/grammar/actions'
|
3
|
+
require 'fabulator/grammar/expr/rules'
|
4
|
+
require 'fabulator/grammar/expr/rule'
|
5
|
+
require 'fabulator/grammar/expr/rule_ref'
|
6
|
+
require 'fabulator/grammar/expr/text'
|
7
|
+
require 'fabulator/grammar/expr/sequence'
|
8
|
+
require 'fabulator/grammar/expr/char_set'
|
9
|
+
require 'fabulator/grammar/expr/any'
|
10
|
+
|
11
|
+
module Fabulator
|
12
|
+
module Grammar
|
13
|
+
class ParserError < StandardError
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
#require 'fabulator/grammar/actions/grammar'
|
2
|
+
|
3
|
+
module Fabulator
|
4
|
+
GRAMMAR_NS = "http://dh.tamu.edu/ns/fabulator/grammar/1.0#"
|
5
|
+
module Grammar
|
6
|
+
module Actions
|
7
|
+
class Lib
|
8
|
+
include Fabulator::ActionLib
|
9
|
+
|
10
|
+
register_namespace GRAMMAR_NS
|
11
|
+
|
12
|
+
#action 'grammar', Grammar
|
13
|
+
|
14
|
+
## reference a grammar name
|
15
|
+
function 'match' do |ctx, args|
|
16
|
+
# first arg is the regex or <rule name>
|
17
|
+
regex = args[0].to_s
|
18
|
+
parser = Fabulator::Grammar::Parser.new
|
19
|
+
compiled = parser.parse(regex, ctx).to_regex
|
20
|
+
if args[1].is_a?(Array)
|
21
|
+
args[1].collect{|a|
|
22
|
+
if a.to_s =~ compiled
|
23
|
+
ctx.root.anon_node(true)
|
24
|
+
else
|
25
|
+
ctx.root.anon_node(false)
|
26
|
+
end
|
27
|
+
}
|
28
|
+
elsif args[1].to_s =~ compiled
|
29
|
+
[ ctx.root.anon_node(true) ]
|
30
|
+
else
|
31
|
+
[ ctx.root.anon_node(false) ]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# function 'tokenize' do |ctx, args|
|
36
|
+
# end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# modifiers: g:minimal, g:ignore-case, g:space, g:ratchet
|
43
|
+
|
44
|
+
# need the concept of hypotheticals here
|
45
|
+
|
46
|
+
# <g:grammar g:namespace=''>
|
47
|
+
# <g:token|g:regex g:name=''>
|
48
|
+
# <g:literal />
|
49
|
+
# <g:capture>...</g:capture>
|
50
|
+
# <g:group>...</g:group>
|
51
|
+
# <g:before>...</g:before>
|
52
|
+
# <g:after>...</g:after>
|
53
|
+
# <g:not-before>...</g:not-before>
|
54
|
+
# <g:not-after>...</g:not-after>
|
55
|
+
# <g:alternatives>...</g:alternatives>
|
56
|
+
# <g:token />
|
57
|
+
# <g:one-or-more>...</g:one-or-more>
|
58
|
+
# <g:zero-or-more>...</g:zero-or-more>
|
59
|
+
# <g:zero-or-one>...</g:zero-or-one>
|
60
|
+
# <g:many g:min='' g:max=''>...</g:many>
|
61
|
+
# </g:token>
|
62
|
+
# <g:rule g:name=''>
|
63
|
+
# <g:when><g:pattern>...</g:pattern>...</g:when>
|
64
|
+
# </g:rule>
|
65
|
+
# </g:grammar>
|