antelope 0.2.4 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,77 @@
1
+ # encoding: utf-8
2
+
3
+ module Antelope
4
+ class Grammar
5
+ # The default modifiers for generation. It's not really
6
+ # recommended to (heh) modify this; however, adding your own
7
+ # modifier is always acceptable.
8
+ DEFAULT_MODIFIERS = [
9
+ [:recognizer, Generation::Recognizer ],
10
+ [:constructor, Generation::Constructor],
11
+ [:tableizer, Generation::Tableizer ]
12
+ ].freeze
13
+
14
+ # Handles the generation of output for the grammar.
15
+ module Generation
16
+ # Generates the output. First, it runs through every given
17
+ # modifier, and instintates it. It then calls every modifier,
18
+ # turns it into a hash, and passes that hash to each of the
19
+ # given generators.
20
+ #
21
+ # @param options [Hash] options.
22
+ # @param generators [Array<Generator>] a list of generators
23
+ # to use in generation.
24
+ # @param modifiers [Array<Array<(Symbol, #call)>>] a list of
25
+ # modifiers to apply to the grammar.
26
+ # @return [void]
27
+ def generate(options = {},
28
+ generators = :guess,
29
+ modifiers = DEFAULT_MODIFIERS)
30
+ pp self
31
+ mods = modifiers.map(&:last)
32
+ .map { |x| x.new(self) }
33
+ mods.each do |mod|
34
+ puts "Running mod #{mod.class}..." if options[:verbose]
35
+ mod.call
36
+ end
37
+ hash = Hash[modifiers.map(&:first).zip(mods)]
38
+ # This is when we'd generate
39
+
40
+ find_generators(generators, options).each do |gen|
41
+ puts "Running generator #{gen}..." if options[:verbose]
42
+ gen.new(self, hash).generate
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ # Find the corresponding generators. If the first argument
49
+ # isn't `:guess`, it returns the first argument. Otherwise,
50
+ # it tries to "intelligently guess" by checking the type from
51
+ # the options _or_ the compiler. If it is unable to find the
52
+ # type, it will raise a {NoTypeError}.
53
+ #
54
+ # @raise [NoTypeError] if it could not determine the type of
55
+ # the generator.
56
+ # @param generators [Symbol, Array<Generator>]
57
+ # @param options [Hash]
58
+ # @return [Array<Generator>]
59
+ def find_generators(generators, options)
60
+ return generators unless generators == :guess
61
+
62
+ generators = [Generator::Output]
63
+
64
+ # command line precedence...
65
+ type = options[:type] || options['type'] ||
66
+ compiler.options.fetch(:type)
67
+
68
+ generators << Generator.generators.fetch(type.to_s)
69
+
70
+ generators
71
+
72
+ rescue KeyError
73
+ raise NoTypeError, "Undefined type #{type}"
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,84 @@
1
+ # encoding: utf-8
2
+
3
+ module Antelope
4
+ class Grammar
5
+ # Handles loading to and from files and strings.
6
+ module Loading
7
+ # Defines class methods on the grammar.
8
+ module ClassMethods
9
+ # Loads a grammar from a file. Assumes the output
10
+ # directory and name from the file name.
11
+ #
12
+ # @param file_name [String] the file name.
13
+ # @return [Grammar]
14
+ # @see #from_string
15
+ def from_file(file_name)
16
+ ext = File.extname(file_name)
17
+ case ext
18
+ when ".rb", ".ate"
19
+ from_dsl_file(file_name)
20
+ when ".ace"
21
+ from_ace_file(file_name)
22
+ else
23
+ raise ArgumentError, "Unexpected file extension #{ext},"\
24
+ " expected one of .rb, .ate, or .ace"
25
+ end
26
+ end
27
+
28
+ def from_dsl_file(file_name)
29
+ body = File.read(file_name)
30
+ output = File.dirname(file_name)
31
+ from_dsl_string(file_name, output, body)
32
+ end
33
+
34
+ def from_ace_file(file_name)
35
+ body = File.read(file_name)
36
+ output = File.dirname(file_name)
37
+ name = File.basename(file_name)
38
+ from_ace_string(name, output, body)
39
+ end
40
+
41
+ # Loads a grammar from a string. First runs the scanner and
42
+ # compiler over the string, and then instantiates a new
43
+ # Grammar from the resultant.
44
+ #
45
+ # @param file [String] the path of the grammar. This is
46
+ # used for eval.
47
+ # @param output [String] the output directory.
48
+ # @param string [String] the grammar body.
49
+ # @return [Grammar]
50
+ # @see DSL::Compiler
51
+ def from_dsl_string(file, output, string)
52
+ eval(string, TOPLEVEL_BINDING, file, 0)
53
+ grammar = Antelope.grammar
54
+ compiler = DSL::Compiler.compile(grammar[1], &grammar[2])
55
+ new(File.basename(file), output, compiler)
56
+ end
57
+
58
+ # Loads a grammar from a string. First runs the scanner and
59
+ # compiler over the string, and then instantiates a new
60
+ # Grammar from the resultant.
61
+ #
62
+ # @param name [String] the name of the grammar.
63
+ # @param output [String] the output directory.
64
+ # @param string [String] the grammar body.
65
+ # @return [Grammar]
66
+ # @see Ace::Scanner
67
+ # @see Ace::Compiler
68
+ def from_ace_string(name, output, string)
69
+ scanner = Ace::Scanner.scan(string, name)
70
+ compiler = Ace::Compiler.compile(scanner)
71
+ new(name, output, compiler)
72
+ end
73
+ end
74
+
75
+ # Extends the grammar with the class methods.
76
+ #
77
+ # @param receiver [Grammar]
78
+ # @see ClassMethods
79
+ def self.included(receiver)
80
+ receiver.extend ClassMethods
81
+ end
82
+ end
83
+ end
84
+ end
@@ -1,12 +1,10 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Antelope
4
- module Ace
5
-
4
+ class Grammar
6
5
  # Defines a precedence. A precedence has a type, tokens, and a
7
6
  # level.
8
- class Precedence < Struct.new(:type, :tokens, :level)
9
-
7
+ Precedence = Struct.new(:type, :tokens, :level) do
10
8
  # @!attribute [rw] type
11
9
  # The type of precedence level. This should be one of
12
10
  # `:left`, `:right`, or `:nonassoc`.
@@ -0,0 +1,64 @@
1
+ # encoding: utf-8
2
+
3
+ require "set"
4
+
5
+ module Antelope
6
+ class Grammar
7
+ # Manages precedence for tokens.
8
+ module Precedences
9
+ # Accesses the generated precedence list. Lazily generates
10
+ # the precedence rules on the go, and then caches it.
11
+ #
12
+ # @return [Array<Ace::Precedence>]
13
+ def precedence
14
+ @_precedence ||= generate_precedence
15
+ end
16
+
17
+ # Finds a precedence rule for a given token. If no direct
18
+ # rule is defined for that token, it will check for a rule
19
+ # defined for the special symbol, `:_`. By default, there
20
+ # is always a rule defined for `:_`.
21
+ #
22
+ # @param token [Ace::Token, Symbol]
23
+ # @return [Ace::Precedence]
24
+ def precedence_for(token)
25
+ token = token.name if token.is_a?(Token)
26
+
27
+ prec = precedence.
28
+ detect { |pr| pr.tokens.include?(token) } ||
29
+ precedence.
30
+ detect { |pr| pr.tokens.include?(:_) }
31
+
32
+ prec
33
+ end
34
+
35
+ private
36
+
37
+ # Generates the precedence rules. Loops through the compiler
38
+ # given precedence settings, and then adds two default
39
+ # precedence rules; one for `:$` (level 0, nonassoc), and one
40
+ # for `:_` (level 1, nonassoc).
41
+ #
42
+ # @return [Array<Ace::Precedence>]
43
+ def generate_precedence
44
+ size = @compiler.options[:prec].size + 1
45
+ index = 0
46
+ precedence = []
47
+
48
+ while index < size - 1
49
+ prec = @compiler.options[:prec][index]
50
+ precedence <<
51
+ Precedence.new(prec[0], prec[1..-1].to_set,
52
+ size - index)
53
+ index += 1
54
+ end
55
+
56
+ precedence <<
57
+ Precedence.new(:nonassoc, [:$end].to_set, 0) <<
58
+ Precedence.new(:nonassoc, [:_].to_set, 1)
59
+ precedence.sort_by(&:level).reverse
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -1,10 +1,9 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Antelope
4
- module Ace
5
-
4
+ class Grammar
6
5
  # Defines a production.
7
- class Production < Struct.new(:label, :items, :block, :prec, :id)
6
+ Production = Struct.new(:label, :items, :block, :prec, :id) do
8
7
  # @!attribute [rw] label
9
8
  # The label (or left-hand side) of the production. This
10
9
  # should be a nonterminal.
@@ -35,11 +34,11 @@ module Antelope
35
34
  #
36
35
  # @param hash [Hash<(Symbol, Object)>]
37
36
  def self.from_hash(hash)
38
- new(hash[:label] || hash["label"],
39
- hash[:items] || hash["items"],
40
- hash[:block] || hash["block"],
41
- hash[:prec] || hash["prec"],
42
- hash[:id] || hash["id"])
37
+ new(hash[:label] || hash['label'],
38
+ hash[:items] || hash['items'],
39
+ hash[:block] || hash['block'],
40
+ hash[:prec] || hash['prec'],
41
+ hash[:id] || hash['id'])
43
42
  end
44
43
 
45
44
  # Create a new version of the production with duplicated values.
@@ -47,10 +46,10 @@ module Antelope
47
46
  # @return [Production]
48
47
  def clone
49
48
  Production.new(label.dup,
50
- items.map(&:dup),
51
- block.dup,
52
- prec.dup,
53
- id)
49
+ items.map(&:dup),
50
+ block.dup,
51
+ prec.dup,
52
+ id)
54
53
  end
55
54
  end
56
55
  end
@@ -0,0 +1,154 @@
1
+ # encoding: utf-8
2
+
3
+ module Antelope
4
+ class Grammar
5
+
6
+ # Manages the productions of the grammar.
7
+ module Productions
8
+
9
+ # Returns a hash of all of the productions. The result is
10
+ # cached.
11
+ #
12
+ # @return [Hash<(Symbol, Array<Production>)>]
13
+ def productions
14
+ @_productions || generate_productions
15
+ end
16
+
17
+ # Returns all productions for all nonterminals, sorted by id.
18
+ #
19
+ # @return [Array<Production>]
20
+ def all_productions
21
+ productions.values.flatten.sort_by(&:id)
22
+ end
23
+
24
+ # Finds a token based on its corresponding symbol. First
25
+ # checks the productions, to see if it's a nonterminal; then,
26
+ # tries to find it in the terminals; otherwise, if the symbol
27
+ # is `error`, it returns a {Token::Error}; if the symbol is
28
+ # `nothing` or `ε`, it returns a {Token::Epsilon}; if it's
29
+ # none of those, it raises an {UndefinedTokenError}.
30
+ #
31
+ # @raise [UndefinedTokenError] if the token doesn't exist.
32
+ # @param value [String, Symbol, #intern] the token's symbol to
33
+ # check.
34
+ # @return [Token]
35
+ def find_token(value)
36
+ value = value.intern
37
+
38
+ if productions.key?(value)
39
+ typed_nonterminals.find { |term| term.name == value } ||
40
+ Token::Nonterminal.new(value)
41
+ elsif terminal = terminals.
42
+ find { |term| term.name == value }
43
+ terminal
44
+ elsif value == :$error || value == :error
45
+ Token::Error.new
46
+ elsif [:nothing, :ε, :"%empty"].include?(value)
47
+ Token::Epsilon.new
48
+ else
49
+ raise UndefinedTokenError, "Could not find a token " \
50
+ "named #{value.inspect}"
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ # Actually generates the productions. Uses the rules from the
57
+ # compiler to construct the productions. Makes two loops over
58
+ # the compiler's rules; the first to tell the grammar that the
59
+ # nonterminal does exist, and the second to actually construct
60
+ # the productions. The first loop is for {#find_token},
61
+ # because otherwise it wouldn't be able to return a
62
+ # nonterminal properly.
63
+ #
64
+ # @return [Hash<(Symbol, Array<Production>)>]
65
+ def generate_productions
66
+ @_productions = {}
67
+ index = 0
68
+
69
+ rules = @compiler.rules.each do |rule|
70
+ productions[rule[:label]] = []
71
+ end
72
+
73
+ while index < rules.size
74
+ rule = rules[index]
75
+ productions[rule[:label]] <<
76
+ generate_production_for(rule, index)
77
+ index += 1
78
+ end
79
+
80
+ productions[:$start] = [default_production]
81
+
82
+ productions
83
+ end
84
+
85
+ # Generates a production for a given compiler rule. Converts
86
+ # the tokens in the set to their {Token} counterparts,
87
+ # and then sets the precedence for the production. If the
88
+ # precedence declaration from the compiler rule is empty,
89
+ # then it'll use the last terminal from the set to check for
90
+ # precedence; otherwise, it'll use the precedence declaration.
91
+ # This is to make sure that every production has a precedence
92
+ # declaration.
93
+ #
94
+ # @param rule [Hash] the compiler's rule.
95
+ # @param id [Numeric] the id for the production.
96
+ # @return [Production]
97
+ def generate_production_for(rule, id)
98
+ left = Token::Nonterminal.new(rule[:label])
99
+ items = rule[:set].map { |_| find_token(_[0]) }
100
+ prec = if rule[:prec].empty?
101
+ items.select(&:terminal?).first
102
+ else
103
+ rule[:prec].intern
104
+ end
105
+
106
+ prec = precedence_for(prec)
107
+ left.type = type_for(rule[:label])
108
+ left.id = rule[:label_id]
109
+
110
+ rule[:set].each_with_index do |tok, i|
111
+ items[i] = items[i].dup
112
+ items[i].id = tok[1]
113
+ end
114
+ items.delete_if(&:epsilon?)
115
+
116
+ Production.new(left, items, rule[:block], prec, id + 1)
117
+ end
118
+
119
+ # Returns the defined type for the given token name.
120
+ # Uses the `%type` directive to infer the corresponding types.
121
+ #
122
+ # @param token [Symbol] the token to check for
123
+ # types.
124
+ def type_for(token)
125
+ token = find_token(token) unless token.is_a?(Token)
126
+
127
+ case token
128
+ when Token::Nonterminal
129
+ token.type
130
+ when Token::Terminal
131
+ token.type
132
+ when Token::Epsilon
133
+ ""
134
+ when Token::Error
135
+ ""
136
+ end
137
+ end
138
+
139
+ # Creates the default production for the grammar. The left
140
+ # hand side of the production is the `:$start` symbol, with
141
+ # the right hand side being the first rule's left-hand side
142
+ # and the terminal `$`. This production is automagically
143
+ # given the last precedence, and an id of 0.
144
+ #
145
+ # @return [Production]
146
+ def default_production
147
+ Production.new(Token::Nonterminal.new(:$start), [
148
+ Token::Nonterminal.new(@compiler.rules.first[:label]),
149
+ Token::Terminal.new(:$end)
150
+ ], "", precedence.last, 0)
151
+ end
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,64 @@
1
+ # encoding: utf-8
2
+
3
+ module Antelope
4
+ class Grammar
5
+
6
+ # Manages a list of the symbols in the grammar.
7
+ module Symbols
8
+
9
+ # A list of all terminals in the grammar. Checks the compiler
10
+ # options for terminals, and then returns an array of
11
+ # terminals. Caches the result.
12
+ #
13
+ # @return [Array<Token::Terminal>]
14
+ def terminals
15
+ @_terminals ||= begin
16
+ @compiler.options.fetch(:terminals) { [] }.map do |v|
17
+ Token::Terminal.new(*v)
18
+ end
19
+ end
20
+ end
21
+
22
+ # A list of all nonterminals in the grammar.
23
+ #
24
+ # @return [Array<Symbol>]
25
+ # @see #productions
26
+ def nonterminals
27
+ @_nonterminals ||= productions.keys
28
+ end
29
+
30
+ # A list of all nonterminals, with types.
31
+ #
32
+ # @return [Array<Token::Nonterminal>>]
33
+ def typed_nonterminals
34
+ @_typed_nonterminals ||= begin
35
+ typed = []
36
+ compiler.options[:nonterminals].each do |data|
37
+ data[1].each do |nonterm|
38
+ typed << Token::Nonterminal.new(nonterm, data[0])
39
+ end
40
+ end
41
+ typed
42
+ end
43
+ end
44
+
45
+ # A list of all symbols in the grammar; includes both
46
+ # terminals and nonterminals.
47
+ #
48
+ # @return [Array<Token::Terminal, Symbol>]
49
+ # @see #terminals
50
+ # @see #nonterminals
51
+ def symbols
52
+ @_symbols ||= terminals + nonterminals
53
+ end
54
+
55
+ # Checks to see if the grammar uses the `error` terminal
56
+ # anywhere.
57
+ #
58
+ # @return [Boolean]
59
+ def contains_error_token?
60
+ all_productions.any? { |_| _.items.any?(&:error?) }
61
+ end
62
+ end
63
+ end
64
+ end
@@ -1,9 +1,8 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Antelope
4
- module Ace
4
+ class Grammar
5
5
  class Token
6
-
7
6
  # Defines an epsilon token. An epsilon token represents
8
7
  # nothing. This is used to say that a nonterminal can
9
8
  # reduce to nothing.
@@ -1,15 +1,13 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Antelope
4
- module Ace
4
+ class Grammar
5
5
  class Token
6
-
7
6
  # Defines an error token. This may be used internally by the
8
7
  # parser when it enters panic mode; any tokens following this
9
8
  # are the synchronisation tokens. This is considered a terminal
10
9
  # for the purposes of rule definitions.
11
10
  class Error < Terminal
12
-
13
11
  # Initialize the error token. Technically takes no arguments.
14
12
  # Sets the name to be `:$error`.
15
13
  def initialize(*)
@@ -1,12 +1,10 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Antelope
4
- module Ace
4
+ class Grammar
5
5
  class Token
6
-
7
6
  # Defines a nonterminal token.
8
7
  class Nonterminal < Token
9
-
10
8
  # (see Token#nonterminal?)
11
9
  def nonterminal?
12
10
  true
@@ -1,12 +1,10 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Antelope
4
- module Ace
4
+ class Grammar
5
5
  class Token
6
-
7
6
  # Defines a terminal token.
8
7
  class Terminal < Token
9
-
10
8
  # (see Token#terminal?)
11
9
  def terminal?
12
10
  true
@@ -1,21 +1,18 @@
1
1
  # encoding: utf-8
2
2
 
3
- require "antelope/ace/token/nonterminal"
4
- require "antelope/ace/token/terminal"
5
- require "antelope/ace/token/epsilon"
6
- require "antelope/ace/token/error"
7
-
3
+ require 'antelope/grammar/token/nonterminal'
4
+ require 'antelope/grammar/token/terminal'
5
+ require 'antelope/grammar/token/epsilon'
6
+ require 'antelope/grammar/token/error'
8
7
 
9
8
  module Antelope
10
- module Ace
11
-
9
+ class Grammar
12
10
  # Defines a token type for productions/rules.
13
11
  #
14
12
  # @abstract This class should be inherited to define a real token.
15
13
  # A base class does not match any token; however, any token can
16
14
  # match the base class.
17
15
  class Token
18
-
19
16
  # The name of the token.
20
17
  #
21
18
  # @return [Symbol]
@@ -138,16 +135,16 @@ module Antelope
138
135
  # @see #name
139
136
  def to_s
140
137
  buf = if @value
141
- @value.inspect
142
- else
143
- @name.to_s
144
- end
138
+ @value.inspect
139
+ else
140
+ @name.to_s
141
+ end
145
142
 
146
- if from or to
147
- buf << "("
143
+ if from || to
144
+ buf << '('
148
145
  buf << "#{from.id}" if from
149
146
  buf << ":#{to.id}" if to
150
- buf << ")"
147
+ buf << ')'
151
148
  end
152
149
 
153
150
  buf
@@ -0,0 +1,68 @@
1
+ # encoding: utf-8
2
+
3
+ require 'hashie'
4
+ require 'antelope/grammar/symbols'
5
+ require 'antelope/grammar/productions'
6
+ require 'antelope/grammar/production'
7
+ require 'antelope/grammar/precedences'
8
+ require 'antelope/grammar/precedence'
9
+ require 'antelope/grammar/loading'
10
+ require 'antelope/grammar/generation'
11
+ require 'antelope/grammar/token'
12
+
13
+ module Antelope
14
+ # Defines a grammar from an Ace file. This handles setting up
15
+ # productions, loading from files, symbols, precedence, and
16
+ # generation.
17
+ class Grammar
18
+ include Symbols
19
+ include Productions
20
+ include Precedences
21
+ include Loading
22
+ include Grammar::Generation
23
+
24
+ # Used by a generation class; this is all the generated states
25
+ # of the grammar.
26
+ #
27
+ # @return [Set<Generation::Recognizer::State>]
28
+ # @see Generation::Recognizer
29
+ attr_accessor :states
30
+
31
+ # The name of the grammar. This is normally assumed from a file
32
+ # name.
33
+ #
34
+ # @return [String]
35
+ attr_accessor :name
36
+
37
+ # The output directory for the grammar. This is normally the
38
+ # same directory as the Ace file.
39
+ #
40
+ # @return [Pathname]
41
+ attr_accessor :output
42
+
43
+ # The compiler for the Ace file.
44
+ #
45
+ # @return [Compiler]
46
+ attr_reader :compiler
47
+
48
+ # Initialize.
49
+ #
50
+ # @param name [String]
51
+ # @param output [String] the output directory. Automagically
52
+ # turned into a Pathname.
53
+ # @param compiler [Compiler]
54
+ def initialize(name, output, compiler)
55
+ @name = name
56
+ @output = Pathname.new(output)
57
+ @compiler = compiler
58
+ end
59
+
60
+ # Extra options from the compiler. This can be used by
61
+ # generators for output information.
62
+ #
63
+ # @return [Hash]
64
+ def options
65
+ compiler.options[:extra]
66
+ end
67
+ end
68
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Antelope
4
4
  # The current running version of antelope.
5
- VERSION = "0.2.4".freeze
5
+ VERSION = '0.3.0'.freeze
6
6
  end