antelope 0.2.4 → 0.3.0

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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +11 -0
  3. data/bin/antelope +3 -3
  4. data/examples/{example.err → example.ace.err} +9 -9
  5. data/examples/{example.inf → example.ace.inf} +57 -9
  6. data/examples/example.ate +70 -0
  7. data/examples/example.ate.err +192 -0
  8. data/examples/example.ate.inf +432 -0
  9. data/lib/antelope/ace/compiler.rb +4 -4
  10. data/lib/antelope/ace/errors.rb +0 -18
  11. data/lib/antelope/ace.rb +6 -12
  12. data/lib/antelope/cli.rb +1 -1
  13. data/lib/antelope/dsl/compiler.rb +117 -0
  14. data/lib/antelope/dsl/contexts/base.rb +29 -0
  15. data/lib/antelope/dsl/contexts/main.rb +63 -0
  16. data/lib/antelope/dsl/contexts/match.rb +24 -0
  17. data/lib/antelope/dsl/contexts/precedence.rb +20 -0
  18. data/lib/antelope/dsl/contexts/production.rb +24 -0
  19. data/lib/antelope/dsl/contexts/terminal.rb +28 -0
  20. data/lib/antelope/dsl/contexts.rb +16 -0
  21. data/lib/antelope/dsl.rb +9 -0
  22. data/lib/antelope/errors.rb +18 -1
  23. data/lib/antelope/generation/constructor/first.rb +10 -12
  24. data/lib/antelope/generation/constructor/follow.rb +6 -6
  25. data/lib/antelope/generation/constructor/nullable.rb +6 -6
  26. data/lib/antelope/generation/constructor.rb +4 -4
  27. data/lib/antelope/generation/recognizer/rule.rb +17 -17
  28. data/lib/antelope/generation/recognizer/state.rb +9 -10
  29. data/lib/antelope/generation/recognizer.rb +8 -11
  30. data/lib/antelope/generation/tableizer.rb +2 -2
  31. data/lib/antelope/generator/base.rb +7 -7
  32. data/lib/antelope/generator/ruby.rb +1 -1
  33. data/lib/antelope/grammar/generation.rb +77 -0
  34. data/lib/antelope/grammar/loading.rb +84 -0
  35. data/lib/antelope/{ace → grammar}/precedence.rb +2 -4
  36. data/lib/antelope/grammar/precedences.rb +64 -0
  37. data/lib/antelope/{ace → grammar}/production.rb +11 -12
  38. data/lib/antelope/grammar/productions.rb +154 -0
  39. data/lib/antelope/grammar/symbols.rb +64 -0
  40. data/lib/antelope/{ace → grammar}/token/epsilon.rb +1 -2
  41. data/lib/antelope/{ace → grammar}/token/error.rb +1 -3
  42. data/lib/antelope/{ace → grammar}/token/nonterminal.rb +1 -3
  43. data/lib/antelope/{ace → grammar}/token/terminal.rb +1 -3
  44. data/lib/antelope/{ace → grammar}/token.rb +12 -15
  45. data/lib/antelope/grammar.rb +68 -0
  46. data/lib/antelope/version.rb +1 -1
  47. data/lib/antelope.rb +12 -6
  48. data/spec/antelope/ace/compiler_spec.rb +6 -6
  49. data/spec/antelope/ace/scanner_spec.rb +7 -7
  50. data/spec/antelope/generation/constructor_spec.rb +131 -0
  51. data/spec/support/grammar_helper.rb +2 -3
  52. metadata +32 -19
  53. data/lib/antelope/ace/grammar/generation.rb +0 -80
  54. data/lib/antelope/ace/grammar/loading.rb +0 -53
  55. data/lib/antelope/ace/grammar/precedences.rb +0 -68
  56. data/lib/antelope/ace/grammar/productions.rb +0 -156
  57. data/lib/antelope/ace/grammar/symbols.rb +0 -66
  58. data/lib/antelope/ace/grammar.rb +0 -69
  59. data/spec/antelope/constructor_spec.rb +0 -133
data/lib/antelope.rb CHANGED
@@ -1,13 +1,19 @@
1
1
  # encoding: utf-8
2
2
 
3
- require "antelope/errors"
4
- require "antelope/generation"
5
- require "antelope/generator"
6
- require "antelope/version"
7
- require "antelope/ace"
8
- require "antelope/template"
3
+ require 'antelope/errors'
4
+ require 'antelope/generation'
5
+ require 'antelope/generator'
6
+ require 'antelope/version'
7
+ require 'antelope/grammar'
8
+ require 'antelope/ace'
9
+ require 'antelope/dsl'
10
+ require 'antelope/template'
9
11
 
10
12
  # Antelope, the compiler compiler.
11
13
  module Antelope
14
+ def self.define(name, options = {}, &block)
15
+ @grammar = [name, options, block]
16
+ end
12
17
 
18
+ class << self; attr_reader :grammar; end
13
19
  end
@@ -43,18 +43,18 @@ describe Ace::Compiler do
43
43
  its(:body) { should =~ /hello/ }
44
44
  its(:options) { should have_key :type }
45
45
 
46
- it "should have the proper terminals" do
46
+ it 'has the proper terminals' do
47
47
  expect(subject.options[:terminals].map(&:first)).to eq [:NUMBER,
48
48
  :SEMICOLON, :ADD, :LPAREN, :RPAREN]
49
49
  end
50
50
 
51
- context "with an unmatched version" do
52
- let :file do "%require \"0.0.0\"\n%%\n%%\n" end
51
+ context 'with an unmatched version' do
52
+ let(:file) { "%require \"0.0.0\"\n%%\n%%\n" }
53
53
 
54
- it "should raise an error" do
55
- expect {
54
+ it 'raises an error' do
55
+ expect do
56
56
  subject
57
- }.to raise_error(Ace::IncompatibleVersionError)
57
+ end.to raise_error(IncompatibleVersionError)
58
58
  end
59
59
  end
60
60
  end
@@ -1,20 +1,20 @@
1
1
  describe Ace::Scanner do
2
2
 
3
- it "properly scans" do
3
+ it 'properly scans' do
4
4
  expect(scan("%test \"a\" hi\n%%\nt: d { { } }\n%%\nhi\n")).to eq [
5
- [:directive, "test", ["a", "hi"]],
5
+ [:directive, 'test', %w(a hi)],
6
6
  [:second],
7
- [:label, "t", nil],
8
- [:part, "d", nil],
9
- [:block, "{ { } }"],
7
+ [:label, 't', nil],
8
+ [:part, 'd', nil],
9
+ [:block, '{ { } }'],
10
10
  [:third],
11
11
  [:copy, "\nhi\n"]
12
12
  ]
13
13
  end
14
14
 
15
- it "throws an error" do
15
+ it 'throws an error' do
16
16
  expect {
17
- scan("% %% %% ")
17
+ scan('% %% %% ')
18
18
  }.to raise_error(Ace::SyntaxError)
19
19
  end
20
20
 
@@ -0,0 +1,131 @@
1
+ describe Generation::Constructor do
2
+ let(:grammar) { double('grammar') }
3
+ let(:terminal) { token(:TERMINAL) }
4
+ let(:epsilon) { token(:epsilon) }
5
+
6
+ subject { described_class.new(grammar) }
7
+
8
+ context '#nullable?' do
9
+ context 'when given an epsilon token' do
10
+ it 'returns true' do
11
+ expect(subject.nullable?(epsilon)).to be true
12
+ end
13
+ end
14
+
15
+ context 'when given a terminal' do
16
+ it 'returns false' do
17
+ expect(subject.nullable?(terminal)).to be false
18
+ end
19
+ end
20
+
21
+ context 'when given an array' do
22
+ context 'with one of the elements not nullable' do
23
+ it 'returns false' do
24
+ expect(subject.nullable?([terminal, epsilon])).to be false
25
+ end
26
+ end
27
+
28
+ context 'with all of the elements nullable' do
29
+ it 'returns true' do
30
+ expect(subject.nullable?([epsilon, epsilon])).to be true
31
+ end
32
+ end
33
+ end
34
+
35
+ context 'when given a nonterminal' do
36
+ let(:grammar) { with_recognizer }
37
+
38
+ context 'with no nullable productions' do
39
+ let(:nonterminal) { Grammar::Token::Nonterminal.new(:l) }
40
+
41
+ it 'returns false' do
42
+ expect(subject.nullable?(nonterminal)).to be false
43
+ end
44
+ end
45
+
46
+ context 'with a nullable production' do
47
+ let(:nonterminal) { Grammar::Token::Nonterminal.new(:e) }
48
+
49
+ it 'returns true' do
50
+ expect(subject.nullable?(nonterminal)).to be true
51
+ end
52
+ end
53
+ end
54
+
55
+ context 'when given a bad argument' do
56
+ it 'raises an error' do
57
+ expect { subject.nullable?(nil) }.to raise_error(ArgumentError)
58
+ end
59
+ end
60
+ end
61
+
62
+ context '#first' do
63
+ context 'when given an epsilon token' do
64
+ it 'generates an empty set' do
65
+ expect(subject.first(epsilon)).to eq Set.new
66
+ end
67
+ end
68
+
69
+ context 'when given a terminal' do
70
+ it 'generates a set' do
71
+ expect(subject.first(terminal)).to eq [terminal].to_set
72
+ end
73
+ end
74
+
75
+ context 'when given an array' do
76
+ let(:terminal2) { token(:terminal, :TERMINAL2) }
77
+
78
+ it 'generates a set' do
79
+ expect(subject.first([epsilon, terminal]))
80
+ .to eq [terminal].to_set
81
+ expect(subject.first([terminal, terminal2]))
82
+ .to eq [terminal].to_set
83
+ end
84
+ end
85
+
86
+ context 'when given a nonterminal' do
87
+ let(:grammar) { with_recognizer }
88
+ let(:nonterminal) { token(:nonterminal, :e) }
89
+
90
+ it 'generates a set' do
91
+ expect(subject.first(nonterminal))
92
+ .to eq [token(:terminal, :IDENT), token(:terminal, :STAR, '*')].to_set
93
+ end
94
+ end
95
+
96
+ context 'when given a bad argument' do
97
+ it 'raises an error' do
98
+ expect { subject.first(nil) }.to raise_error(ArgumentError)
99
+ end
100
+ end
101
+ end
102
+
103
+ context '#follow' do
104
+ context 'when given a bad argument' do
105
+ it 'raises an error' do
106
+ expect { subject.follow(nil) }.to raise_error(ArgumentError)
107
+ end
108
+ end
109
+
110
+ context 'when given a nonterminal' do
111
+ let(:grammar) { with_recognizer }
112
+ let(:nonterminal) { token(:nonterminal, :l) }
113
+
114
+ before do
115
+ subject.productions.merge grammar.productions.values.flatten
116
+ end
117
+
118
+ it 'generates a set' do
119
+ expect(subject.follow(nonterminal)).to eq [
120
+ token(:terminal, :EQUALS, '='),
121
+ token(:terminal, :'$end')
122
+ ].to_set
123
+ end
124
+ end
125
+ end
126
+
127
+ def token(type, name = nil, value = nil, ttype = nil, id = nil)
128
+ type = Grammar::Token.const_get(type.to_s.capitalize)
129
+ type.new(name, ttype, id, value)
130
+ end
131
+ end
@@ -1,13 +1,12 @@
1
1
  module GrammarHelper
2
-
3
2
  def grammar_for(grammar_file = "simple")
4
3
  source_path = Pathname.new("../../fixtures").expand_path(__FILE__)
5
- Ace::Grammar.from_file(source_path.children.select(&:file?)
4
+ Grammar.from_file(source_path.children.select(&:file?)
6
5
  .find { |x| x.to_s =~ /#{Regexp.escape(grammar_file)}\..*\z/ }.to_s)
7
6
  end
8
7
 
9
8
  def with_recognizer(grammar = simple_grammar)
10
- recognizer = Generation::Recognizer.new(grammar).call
9
+ Generation::Recognizer.new(grammar).call
11
10
  grammar
12
11
  end
13
12
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: antelope
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Rodi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-22 00:00:00.000000000 Z
11
+ date: 2015-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hashie
@@ -104,6 +104,7 @@ extra_rdoc_files: []
104
104
  files:
105
105
  - ".gitignore"
106
106
  - ".rspec"
107
+ - ".rubocop.yml"
107
108
  - ".travis.yml"
108
109
  - ".yardopts"
109
110
  - CONTRIBUTING.md
@@ -117,33 +118,32 @@ files:
117
118
  - bin/antelope
118
119
  - examples/deterministic.ace
119
120
  - examples/example.ace
120
- - examples/example.err
121
- - examples/example.inf
121
+ - examples/example.ace.err
122
+ - examples/example.ace.inf
123
+ - examples/example.ate
124
+ - examples/example.ate.err
125
+ - examples/example.ate.inf
122
126
  - examples/liquidscript.ace
123
127
  - examples/simple.ace
124
128
  - lib/antelope.rb
125
129
  - lib/antelope/ace.rb
126
130
  - lib/antelope/ace/compiler.rb
127
131
  - lib/antelope/ace/errors.rb
128
- - lib/antelope/ace/grammar.rb
129
- - lib/antelope/ace/grammar/generation.rb
130
- - lib/antelope/ace/grammar/loading.rb
131
- - lib/antelope/ace/grammar/precedences.rb
132
- - lib/antelope/ace/grammar/productions.rb
133
- - lib/antelope/ace/grammar/symbols.rb
134
- - lib/antelope/ace/precedence.rb
135
- - lib/antelope/ace/production.rb
136
132
  - lib/antelope/ace/scanner.rb
137
133
  - lib/antelope/ace/scanner/argument.rb
138
134
  - lib/antelope/ace/scanner/first.rb
139
135
  - lib/antelope/ace/scanner/second.rb
140
136
  - lib/antelope/ace/scanner/third.rb
141
- - lib/antelope/ace/token.rb
142
- - lib/antelope/ace/token/epsilon.rb
143
- - lib/antelope/ace/token/error.rb
144
- - lib/antelope/ace/token/nonterminal.rb
145
- - lib/antelope/ace/token/terminal.rb
146
137
  - lib/antelope/cli.rb
138
+ - lib/antelope/dsl.rb
139
+ - lib/antelope/dsl/compiler.rb
140
+ - lib/antelope/dsl/contexts.rb
141
+ - lib/antelope/dsl/contexts/base.rb
142
+ - lib/antelope/dsl/contexts/main.rb
143
+ - lib/antelope/dsl/contexts/match.rb
144
+ - lib/antelope/dsl/contexts/precedence.rb
145
+ - lib/antelope/dsl/contexts/production.rb
146
+ - lib/antelope/dsl/contexts/terminal.rb
147
147
  - lib/antelope/errors.rb
148
148
  - lib/antelope/generation.rb
149
149
  - lib/antelope/generation/constructor.rb
@@ -179,6 +179,19 @@ files:
179
179
  - lib/antelope/generator/templates/html/js.ant
180
180
  - lib/antelope/generator/templates/info.ant
181
181
  - lib/antelope/generator/templates/ruby.ant
182
+ - lib/antelope/grammar.rb
183
+ - lib/antelope/grammar/generation.rb
184
+ - lib/antelope/grammar/loading.rb
185
+ - lib/antelope/grammar/precedence.rb
186
+ - lib/antelope/grammar/precedences.rb
187
+ - lib/antelope/grammar/production.rb
188
+ - lib/antelope/grammar/productions.rb
189
+ - lib/antelope/grammar/symbols.rb
190
+ - lib/antelope/grammar/token.rb
191
+ - lib/antelope/grammar/token/epsilon.rb
192
+ - lib/antelope/grammar/token/error.rb
193
+ - lib/antelope/grammar/token/nonterminal.rb
194
+ - lib/antelope/grammar/token/terminal.rb
182
195
  - lib/antelope/template.rb
183
196
  - lib/antelope/template/compiler.rb
184
197
  - lib/antelope/template/errors.rb
@@ -187,7 +200,7 @@ files:
187
200
  - optimizations.txt
188
201
  - spec/antelope/ace/compiler_spec.rb
189
202
  - spec/antelope/ace/scanner_spec.rb
190
- - spec/antelope/constructor_spec.rb
203
+ - spec/antelope/generation/constructor_spec.rb
191
204
  - spec/antelope/template_spec.rb
192
205
  - spec/fixtures/simple.ace
193
206
  - spec/spec_helper.rb
@@ -222,7 +235,7 @@ summary: A compiler compiler, written in ruby.
222
235
  test_files:
223
236
  - spec/antelope/ace/compiler_spec.rb
224
237
  - spec/antelope/ace/scanner_spec.rb
225
- - spec/antelope/constructor_spec.rb
238
+ - spec/antelope/generation/constructor_spec.rb
226
239
  - spec/antelope/template_spec.rb
227
240
  - spec/fixtures/simple.ace
228
241
  - spec/spec_helper.rb
@@ -1,80 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Antelope
4
- module Ace
5
- class Grammar
6
-
7
- # The default modifiers for generation. It's not really
8
- # recommended to (heh) modify this; however, adding your own
9
- # modifier is always acceptable.
10
- DEFAULT_MODIFIERS = [
11
- [:recognizer, Generation::Recognizer ],
12
- [:constructor, Generation::Constructor],
13
- [:tableizer, Generation::Tableizer ]
14
- ].freeze
15
-
16
- # Handles the generation of output for the grammar.
17
- module Generation
18
-
19
- # Generates the output. First, it runs through every given
20
- # modifier, and instintates it. It then calls every modifier,
21
- # turns it into a hash, and passes that hash to each of the
22
- # given generators.
23
- #
24
- # @param options [Hash] options.
25
- # @param generators [Array<Generator>] a list of generators
26
- # to use in generation.
27
- # @param modifiers [Array<Array<(Symbol, #call)>>] a list of
28
- # modifiers to apply to the grammar.
29
- # @return [void]
30
- def generate(options = {},
31
- generators = :guess,
32
- modifiers = DEFAULT_MODIFIERS)
33
- mods = modifiers.map(&:last).
34
- map { |x| x.new(self) }
35
- mods.each do |mod|
36
- puts "Running mod #{mod.class}..." if options[:verbose]
37
- mod.call
38
- end
39
- hash = Hash[modifiers.map(&:first).zip(mods)]
40
- # This is when we'd generate
41
-
42
- find_generators(generators, options).each do |gen|
43
- puts "Running generator #{gen}..." if options[:verbose]
44
- gen.new(self, hash).generate
45
- end
46
- end
47
-
48
- private
49
-
50
- # Find the corresponding generators. If the first argument
51
- # isn't `:guess`, it returns the first argument. Otherwise,
52
- # it tries to "intelligently guess" by checking the type from
53
- # the options _or_ the compiler. If it is unable to find the
54
- # type, it will raise a {NoTypeError}.
55
- #
56
- # @raise [NoTypeError] if it could not determine the type of
57
- # the generator.
58
- # @param generators [Symbol, Array<Generator>]
59
- # @param options [Hash]
60
- # @return [Array<Generator>]
61
- def find_generators(generators, options)
62
- return generators unless generators == :guess
63
-
64
- generators = [Generator::Output]
65
-
66
- # command line precedence...
67
- type = options[:type] || options["type"] ||
68
- compiler.options.fetch(:type)
69
-
70
- generators << Generator.generators.fetch(type)
71
-
72
- generators
73
-
74
- rescue KeyError
75
- raise NoTypeError, "Undefined type #{type}"
76
- end
77
- end
78
- end
79
- end
80
- end
@@ -1,53 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Antelope
4
- module Ace
5
- class Grammar
6
-
7
- # Handles loading to and from files and strings.
8
- module Loading
9
-
10
- # Defines class methods on the grammar.
11
- module ClassMethods
12
-
13
- # Loads a grammar from a file. Assumes the output
14
- # directory and name from the file name.
15
- #
16
- # @param file_name [String] the file name.
17
- # @return [Grammar]
18
- # @see #from_string
19
- def from_file(file_name)
20
- body = File.read(file_name)
21
- output = File.dirname(file_name)
22
- name = File.basename(file_name).gsub(/\.[A-Za-z]+/, "")
23
- from_string(name, output, body)
24
- end
25
-
26
- # Loads a grammar from a string. First runs the scanner and
27
- # compiler over the string, and then instantiates a new
28
- # Grammar from the resultant.
29
- #
30
- # @param name [String] the name of the grammar.
31
- # @param output [String] the output directory.
32
- # @param string [String] the grammar body.
33
- # @return [Grammar]
34
- # @see Ace::Scanner
35
- # @see Ace::Compiler
36
- def from_string(name, output, string)
37
- scanner = Ace::Scanner.scan(string, name)
38
- compiler = Ace::Compiler.compile(scanner)
39
- new(name, output, compiler)
40
- end
41
- end
42
-
43
- # Extends the grammar with the class methods.
44
- #
45
- # @param receiver [Grammar]
46
- # @see ClassMethods
47
- def self.included(receiver)
48
- receiver.extend ClassMethods
49
- end
50
- end
51
- end
52
- end
53
- end
@@ -1,68 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require "set"
4
-
5
- module Antelope
6
- module Ace
7
- class Grammar
8
-
9
- # Manages precedence for tokens.
10
- module Precedences
11
-
12
- # Accesses the generated precedence list. Lazily generates
13
- # the precedence rules on the go, and then caches it.
14
- #
15
- # @return [Array<Ace::Precedence>]
16
- def precedence
17
- @_precedence ||= generate_precedence
18
- end
19
-
20
- # Finds a precedence rule for a given token. If no direct
21
- # rule is defined for that token, it will check for a rule
22
- # defined for the special symbol, `:_`. By default, there
23
- # is always a rule defined for `:_`.
24
- #
25
- # @param token [Ace::Token, Symbol]
26
- # @return [Ace::Precedence]
27
- def precedence_for(token)
28
- token = token.name if token.is_a?(Token)
29
-
30
- prec = precedence.
31
- detect { |pr| pr.tokens.include?(token) } ||
32
- precedence.
33
- detect { |pr| pr.tokens.include?(:_) }
34
-
35
- prec
36
- end
37
-
38
- private
39
-
40
- # Generates the precedence rules. Loops through the compiler
41
- # given precedence settings, and then adds two default
42
- # precedence rules; one for `:$` (level 0, nonassoc), and one
43
- # for `:_` (level 1, nonassoc).
44
- #
45
- # @return [Array<Ace::Precedence>]
46
- def generate_precedence
47
- size = @compiler.options[:prec].size + 1
48
- index = 0
49
- precedence = []
50
-
51
- while index < size - 1
52
- prec = @compiler.options[:prec][index]
53
- precedence <<
54
- Ace::Precedence.new(prec[0], prec[1..-1].to_set,
55
- size - index)
56
- index += 1
57
- end
58
-
59
- precedence <<
60
- Ace::Precedence.new(:nonassoc, [:$end].to_set, 0) <<
61
- Ace::Precedence.new(:nonassoc, [:_].to_set, 1)
62
- precedence.sort_by(&:level).reverse
63
- end
64
-
65
- end
66
- end
67
- end
68
- end