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
@@ -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