antelope 0.3.2 → 0.4.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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +25 -25
  3. data/.rspec +3 -3
  4. data/.travis.yml +10 -10
  5. data/.yardopts +7 -7
  6. data/CONTRIBUTING.md +50 -38
  7. data/GENERATORS.md +180 -124
  8. data/Gemfile +7 -7
  9. data/LICENSE.txt +22 -22
  10. data/README.md +240 -104
  11. data/Rakefile +2 -2
  12. data/TODO.md +58 -58
  13. data/antelope.gemspec +29 -28
  14. data/bin/antelope +7 -7
  15. data/examples/deterministic.ace +35 -35
  16. data/examples/example.ace +52 -51
  17. data/examples/example.ace.err +192 -192
  18. data/examples/example.ace.inf +432 -432
  19. data/examples/example.ate +70 -70
  20. data/examples/example.ate.err +192 -192
  21. data/examples/example.ate.inf +432 -432
  22. data/examples/liquidscript.ace +233 -233
  23. data/examples/simple.ace +22 -22
  24. data/lib/antelope/ace/compiler.rb +334 -334
  25. data/lib/antelope/ace/errors.rb +30 -30
  26. data/lib/antelope/ace/scanner/argument.rb +57 -57
  27. data/lib/antelope/ace/scanner/first.rb +89 -89
  28. data/lib/antelope/ace/scanner/second.rb +178 -178
  29. data/lib/antelope/ace/scanner/third.rb +27 -27
  30. data/lib/antelope/ace/scanner.rb +144 -144
  31. data/lib/antelope/ace.rb +47 -47
  32. data/lib/antelope/cli.rb +60 -60
  33. data/lib/antelope/errors.rb +25 -25
  34. data/lib/antelope/generation/constructor/first.rb +86 -86
  35. data/lib/antelope/generation/constructor/follow.rb +105 -105
  36. data/lib/antelope/generation/constructor/nullable.rb +64 -64
  37. data/lib/antelope/generation/constructor.rb +127 -127
  38. data/lib/antelope/generation/errors.rb +17 -17
  39. data/lib/antelope/generation/null.rb +13 -13
  40. data/lib/antelope/generation/recognizer/rule.rb +216 -216
  41. data/lib/antelope/generation/recognizer/state.rb +129 -129
  42. data/lib/antelope/generation/recognizer.rb +177 -177
  43. data/lib/antelope/generation/tableizer.rb +176 -176
  44. data/lib/antelope/generation.rb +15 -15
  45. data/lib/antelope/generator/base/coerce.rb +115 -0
  46. data/lib/antelope/generator/base/extra.rb +50 -0
  47. data/lib/antelope/generator/base.rb +134 -264
  48. data/lib/antelope/generator/c.rb +11 -11
  49. data/lib/antelope/generator/c_header.rb +105 -105
  50. data/lib/antelope/generator/c_source.rb +39 -39
  51. data/lib/antelope/generator/error.rb +34 -34
  52. data/lib/antelope/generator/group.rb +60 -57
  53. data/lib/antelope/generator/html.rb +51 -51
  54. data/lib/antelope/generator/info.rb +47 -47
  55. data/lib/antelope/generator/null.rb +18 -18
  56. data/lib/antelope/generator/output.rb +17 -17
  57. data/lib/antelope/generator/ruby.rb +112 -79
  58. data/lib/antelope/generator/templates/c_header.ant +36 -36
  59. data/lib/antelope/generator/templates/c_source.ant +202 -202
  60. data/lib/antelope/generator/templates/error.erb +40 -0
  61. data/lib/antelope/generator/templates/html/antelope.css +53 -1
  62. data/lib/antelope/generator/templates/html/antelope.html +82 -1
  63. data/lib/antelope/generator/templates/html/antelope.js +9 -1
  64. data/lib/antelope/generator/templates/html/css.ant +53 -53
  65. data/lib/antelope/generator/templates/html/html.ant +82 -82
  66. data/lib/antelope/generator/templates/html/js.ant +9 -9
  67. data/lib/antelope/generator/templates/info.erb +61 -0
  68. data/lib/antelope/generator/templates/{ruby.ant → ruby.erb} +171 -178
  69. data/lib/antelope/generator.rb +62 -66
  70. data/lib/antelope/grammar/generation.rb +76 -76
  71. data/lib/antelope/grammar/loading.rb +84 -84
  72. data/lib/antelope/grammar/precedence.rb +59 -59
  73. data/lib/antelope/grammar/precedences.rb +64 -64
  74. data/lib/antelope/grammar/production.rb +56 -56
  75. data/lib/antelope/grammar/productions.rb +154 -154
  76. data/lib/antelope/grammar/symbols.rb +64 -64
  77. data/lib/antelope/grammar/token/epsilon.rb +23 -23
  78. data/lib/antelope/grammar/token/error.rb +24 -24
  79. data/lib/antelope/grammar/token/nonterminal.rb +15 -15
  80. data/lib/antelope/grammar/token/terminal.rb +15 -15
  81. data/lib/antelope/grammar/token.rb +231 -231
  82. data/lib/antelope/grammar.rb +68 -68
  83. data/lib/antelope/version.rb +6 -6
  84. data/lib/antelope.rb +18 -19
  85. data/optimizations.txt +42 -42
  86. data/spec/antelope/ace/compiler_spec.rb +60 -60
  87. data/spec/antelope/ace/scanner_spec.rb +27 -27
  88. data/spec/antelope/generation/constructor_spec.rb +131 -131
  89. data/spec/fixtures/simple.ace +22 -22
  90. data/spec/spec_helper.rb +39 -39
  91. data/spec/support/benchmark_helper.rb +5 -5
  92. data/spec/support/grammar_helper.rb +14 -14
  93. data/subl/Ace (Ruby).JSON-tmLanguage +94 -94
  94. data/subl/Ace (Ruby).tmLanguage +153 -153
  95. metadata +22 -11
  96. data/lib/antelope/generator/templates/error.ant +0 -34
  97. data/lib/antelope/generator/templates/info.ant +0 -53
  98. data/lib/antelope/template/compiler.rb +0 -78
  99. data/lib/antelope/template/errors.rb +0 -9
  100. data/lib/antelope/template/scanner.rb +0 -109
  101. data/lib/antelope/template.rb +0 -64
  102. data/spec/antelope/template_spec.rb +0 -50
@@ -1,129 +1,129 @@
1
- # encoding: utf-8
2
-
3
- require 'forwardable'
4
- require 'securerandom'
5
-
6
- module Antelope
7
- module Generation
8
- class Recognizer
9
-
10
- # A state within the parser. A state has a set of rules, as
11
- # well as transitions on those rules.
12
- class State
13
-
14
- # All of the rules in this state.
15
- #
16
- # @return [Set<Rule>]
17
- attr_reader :rules
18
-
19
- # All of the transitions that can be made on this state.
20
- #
21
- # @return [Hash<(Symbol, State)>]
22
- attr_reader :transitions
23
-
24
- # The id of this state. This starts off as a string of
25
- # hexadecmial characters, but after all of the states are
26
- # finalized, this becomes a numeric.
27
- #
28
- # @return [String, Numeric]
29
- attr_accessor :id
30
-
31
- include Enumerable
32
- extend Forwardable
33
-
34
- def_delegator :@rules, :each
35
-
36
- # Initialize the state.
37
- def initialize
38
- @rules = Set.new
39
- @transitions = {}
40
- @id = format('%10x', object_id)
41
- end
42
-
43
- # Gives a nice string representation of the state.
44
- #
45
- # @return [String]
46
- def inspect
47
- "#<#{self.class} id=#{id} " \
48
- "transitions=[#{transitions.keys.join(', ')}] " \
49
- "rules=[{#{rules.to_a.join('} {')}}]>"
50
- end
51
-
52
- # Merges another state with this state. It copies all of the
53
- # rules into this state, and then merges the transitions on
54
- # the given state to this state. It then returns self.
55
- #
56
- # @raise [ArgumentError] if the given argument is not a state.
57
- # @param other [State] the state to merge.
58
- # @return [self]
59
- def merge!(other)
60
- raise ArgumentError, "Expected #{self.class}, " \
61
- "got #{other.class}" unless other.is_a? State
62
-
63
- self << other
64
- transitions.merge! other.transitions
65
-
66
- self
67
- end
68
-
69
- # Finds the rule that match the given production. It
70
- # uses fuzzy equality checking. It returns the first rule
71
- # that matches.
72
- #
73
- # @param production [Rule] the rule to compare.
74
- # @return [Rule?]
75
- def rule_for(production)
76
- rules.find { |rule| production === rule }
77
- end
78
-
79
- # Appends the given object to this state. The given object
80
- # must be a state or a rule. If it's a state, it appends all
81
- # of the rules in the state to this state. If it's a rule, it
82
- # adds the rule to our rules.
83
- #
84
- # @raise [ArgumentError] if the argument isn't a {State} or a
85
- # {Rule}.
86
- # @param rule [State, Rule] the object to append.
87
- # @return [self]
88
- def <<(rule)
89
- case rule
90
- when State
91
- rule.rules.map(&:clone).each { |r| self << r }
92
- when Rule
93
- rules << rule
94
- when Array, Set
95
- rule.each do |part|
96
- self << part
97
- end
98
- else
99
- raise ArgumentError, "Expected State or Rule, " \
100
- "got #{rule.class}"
101
- end
102
-
103
- self
104
- end
105
-
106
- alias_method :push, :<<
107
-
108
- # Check to see if this state is fuzzily equivalent to another
109
- # state. It does this by checking if the transitions are
110
- # equivalent, and then that the rules are fuzzily equivalent.
111
- # Ideally, the method is commutative; that is,
112
- # `(a === b) == (b === a)`.
113
- #
114
- # @param other [State] the state to check.
115
- # @return [Boolean]
116
- # @see Rule#===
117
- def ===(other)
118
- return super unless other.is_a? State
119
-
120
- other_rules = other.rules.to_a
121
- other.transitions == transitions &&
122
- rules.size == other_rules.size &&
123
- rules.each_with_index
124
- .all? { |rule, i| rule === other_rules[i] }
125
- end
126
- end
127
- end
128
- end
129
- end
1
+ # encoding: utf-8
2
+
3
+ require 'forwardable'
4
+ require 'securerandom'
5
+
6
+ module Antelope
7
+ module Generation
8
+ class Recognizer
9
+
10
+ # A state within the parser. A state has a set of rules, as
11
+ # well as transitions on those rules.
12
+ class State
13
+
14
+ # All of the rules in this state.
15
+ #
16
+ # @return [Set<Rule>]
17
+ attr_reader :rules
18
+
19
+ # All of the transitions that can be made on this state.
20
+ #
21
+ # @return [Hash<(Symbol, State)>]
22
+ attr_reader :transitions
23
+
24
+ # The id of this state. This starts off as a string of
25
+ # hexadecmial characters, but after all of the states are
26
+ # finalized, this becomes a numeric.
27
+ #
28
+ # @return [String, Numeric]
29
+ attr_accessor :id
30
+
31
+ include Enumerable
32
+ extend Forwardable
33
+
34
+ def_delegator :@rules, :each
35
+
36
+ # Initialize the state.
37
+ def initialize
38
+ @rules = Set.new
39
+ @transitions = {}
40
+ @id = format('%10x', object_id)
41
+ end
42
+
43
+ # Gives a nice string representation of the state.
44
+ #
45
+ # @return [String]
46
+ def inspect
47
+ "#<#{self.class} id=#{id} " \
48
+ "transitions=[#{transitions.keys.join(', ')}] " \
49
+ "rules=[{#{rules.to_a.join('} {')}}]>"
50
+ end
51
+
52
+ # Merges another state with this state. It copies all of the
53
+ # rules into this state, and then merges the transitions on
54
+ # the given state to this state. It then returns self.
55
+ #
56
+ # @raise [ArgumentError] if the given argument is not a state.
57
+ # @param other [State] the state to merge.
58
+ # @return [self]
59
+ def merge!(other)
60
+ raise ArgumentError, "Expected #{self.class}, " \
61
+ "got #{other.class}" unless other.is_a? State
62
+
63
+ self << other
64
+ transitions.merge! other.transitions
65
+
66
+ self
67
+ end
68
+
69
+ # Finds the rule that match the given production. It
70
+ # uses fuzzy equality checking. It returns the first rule
71
+ # that matches.
72
+ #
73
+ # @param production [Rule] the rule to compare.
74
+ # @return [Rule?]
75
+ def rule_for(production)
76
+ rules.find { |rule| production === rule }
77
+ end
78
+
79
+ # Appends the given object to this state. The given object
80
+ # must be a state or a rule. If it's a state, it appends all
81
+ # of the rules in the state to this state. If it's a rule, it
82
+ # adds the rule to our rules.
83
+ #
84
+ # @raise [ArgumentError] if the argument isn't a {State} or a
85
+ # {Rule}.
86
+ # @param rule [State, Rule] the object to append.
87
+ # @return [self]
88
+ def <<(rule)
89
+ case rule
90
+ when State
91
+ rule.rules.map(&:clone).each { |r| self << r }
92
+ when Rule
93
+ rules << rule
94
+ when Array, Set
95
+ rule.each do |part|
96
+ self << part
97
+ end
98
+ else
99
+ raise ArgumentError, "Expected State or Rule, " \
100
+ "got #{rule.class}"
101
+ end
102
+
103
+ self
104
+ end
105
+
106
+ alias_method :push, :<<
107
+
108
+ # Check to see if this state is fuzzily equivalent to another
109
+ # state. It does this by checking if the transitions are
110
+ # equivalent, and then that the rules are fuzzily equivalent.
111
+ # Ideally, the method is commutative; that is,
112
+ # `(a === b) == (b === a)`.
113
+ #
114
+ # @param other [State] the state to check.
115
+ # @return [Boolean]
116
+ # @see Rule#===
117
+ def ===(other)
118
+ return super unless other.is_a? State
119
+
120
+ other_rules = other.rules.to_a
121
+ other.transitions == transitions &&
122
+ rules.size == other_rules.size &&
123
+ rules.each_with_index
124
+ .all? { |rule, i| rule === other_rules[i] }
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -1,177 +1,177 @@
1
- # encoding: utf-8
2
-
3
- require 'antelope/generation/recognizer/rule'
4
- require 'antelope/generation/recognizer/state'
5
-
6
- module Antelope
7
- module Generation
8
- # Recognizes all of the states in the grammar.
9
- #
10
- # @see http://redjazz96.tumblr.com/post/88446352960
11
- class Recognizer
12
- # A list of all of the states in the grammar.
13
- #
14
- # @return [Set<State>]
15
- attr_reader :states
16
-
17
- # The initial state. This is the state that is constructed from
18
- # the rule with the left-hand side being `$start`.
19
- #
20
- # @return [State]
21
- attr_reader :start
22
-
23
- # The grammar that the recognizer is running off of.
24
- #
25
- # @return [Grammar]
26
- attr_reader :grammar
27
-
28
- # Initialize the recognizer.
29
- #
30
- # @param grammar [Grammar]
31
- def initialize(grammar)
32
- @grammar = grammar
33
- @states = Set.new
34
- @map = {}
35
- end
36
-
37
- # Runs the recognizer. After all states have been created, it
38
- # resets the state ids into a more friendly form (they were
39
- # originally hexadecimal, see {State#initialize}), and then
40
- # resets the rule ids in each state into a more friendly form
41
- # (they were also originally hexadecmial, see {Rule#initialize}
42
- # ).
43
- #
44
- # @see #compute_initial_state
45
- # @return [void]
46
- def call
47
- @states = Set.new
48
- @start = compute_initial_state
49
- redefine_state_ids
50
- redefine_rule_ids
51
- grammar.states = states
52
- end
53
-
54
- # Computes the initial state. Starting with the default
55
- # production of `$start`, it then generates the whole state
56
- # and then the spawned states from it.
57
- #
58
- # @return [State]
59
- def compute_initial_state
60
- production = grammar.productions[:$start][0]
61
- rule = Rule.new(production, 0)
62
- compute_whole_state(rule)
63
- end
64
-
65
- # Computes the entire initial state from the initial rule.
66
- # It starts with a blank state, adds the initial rule to it, and
67
- # then generates the closure for that state; it then computes
68
- # the rest of the states in the grammar.
69
- #
70
- # @param rule [Rule] the initial rule.
71
- # @return [State]
72
- def compute_whole_state(rule)
73
- state = State.new
74
- state << rule
75
- compute_closure(state)
76
- states << state
77
- compute_states
78
- state
79
- end
80
-
81
- # Computes all states. Uses a fix point iteration to determine
82
- # when no states have been added. Loops through every state and
83
- # every rule, looking for rules that have an active nonterminal
84
- # and computing the closure for said rule.
85
- #
86
- # @return [void]
87
- # @see #compute_closure
88
- def compute_states
89
- fixed_point(states) do
90
- states.dup.each do |state|
91
- compute_gotos(state)
92
- end
93
- end
94
- end
95
-
96
- # Given a state, it does a fixed point iteration on the rules of
97
- # the state that have an active nonterminal, and add the
98
- # corresponding production rules to the state.
99
- #
100
- # @return [void]
101
- def compute_closure(state)
102
- fixed_point(state.rules) do
103
- state.rules.select { |r| r.active.nonterminal? }.each do |rule|
104
- grammar.productions[rule.active.name].each do |prod|
105
- state << Rule.new(prod, 0)
106
- end
107
- end
108
- end
109
- end
110
-
111
- def compute_gotos(state)
112
- actives = state.rules.map(&:active).select(&:name)
113
-
114
- actives.each do |active|
115
- next if state.transitions[active.name]
116
- rules = state.rules
117
- .select { |r| r.active == active && r.succ? }
118
- .map(&:succ).to_set
119
- s = states.find { |st| rules.subset? st.rules } || begin
120
- s = State.new << rules
121
- compute_closure(s)
122
- states << s
123
- s
124
- end
125
-
126
- state.transitions[active.name] = s
127
- end
128
- end
129
-
130
- private
131
-
132
- # Changes the IDs of the states into a more friendly format.
133
- #
134
- # @return [void]
135
- def redefine_state_ids
136
- states.each_with_index do |state, i|
137
- state.id = i
138
- end
139
- end
140
-
141
- # Redefines all of the rule ids to make them more friendly.
142
- # Every rule in every state is given a unique ID, reguardless if
143
- # the rules are equivalent.
144
- #
145
- # @return [void]
146
- def redefine_rule_ids
147
- start = 0
148
-
149
- states.each do |state|
150
- state.rules.each do |rule|
151
- rule.id = start
152
- start += 1
153
- end
154
- end
155
- end
156
-
157
- # Begins a fixed point iteration on the given enumerable. It
158
- # initializes the added elements to one; then, while the number
159
- # of added elements is not zero, it yields and checks for added
160
- # elements.
161
- #
162
- # @param enum [Enumerable]
163
- # @yield for every iteration. Guarenteed to do so at least
164
- # once.
165
- # @return [void]
166
- def fixed_point(enum)
167
- added = 1
168
-
169
- until added.zero?
170
- added = enum.size
171
- yield
172
- added = enum.size - added
173
- end
174
- end
175
- end
176
- end
177
- end
1
+ # encoding: utf-8
2
+
3
+ require 'antelope/generation/recognizer/rule'
4
+ require 'antelope/generation/recognizer/state'
5
+
6
+ module Antelope
7
+ module Generation
8
+ # Recognizes all of the states in the grammar.
9
+ #
10
+ # @see http://redjazz96.tumblr.com/post/88446352960
11
+ class Recognizer
12
+ # A list of all of the states in the grammar.
13
+ #
14
+ # @return [Set<State>]
15
+ attr_reader :states
16
+
17
+ # The initial state. This is the state that is constructed from
18
+ # the rule with the left-hand side being `$start`.
19
+ #
20
+ # @return [State]
21
+ attr_reader :start
22
+
23
+ # The grammar that the recognizer is running off of.
24
+ #
25
+ # @return [Grammar]
26
+ attr_reader :grammar
27
+
28
+ # Initialize the recognizer.
29
+ #
30
+ # @param grammar [Grammar]
31
+ def initialize(grammar)
32
+ @grammar = grammar
33
+ @states = Set.new
34
+ @map = {}
35
+ end
36
+
37
+ # Runs the recognizer. After all states have been created, it
38
+ # resets the state ids into a more friendly form (they were
39
+ # originally hexadecimal, see {State#initialize}), and then
40
+ # resets the rule ids in each state into a more friendly form
41
+ # (they were also originally hexadecmial, see {Rule#initialize}
42
+ # ).
43
+ #
44
+ # @see #compute_initial_state
45
+ # @return [void]
46
+ def call
47
+ @states = Set.new
48
+ @start = compute_initial_state
49
+ redefine_state_ids
50
+ redefine_rule_ids
51
+ grammar.states = states
52
+ end
53
+
54
+ # Computes the initial state. Starting with the default
55
+ # production of `$start`, it then generates the whole state
56
+ # and then the spawned states from it.
57
+ #
58
+ # @return [State]
59
+ def compute_initial_state
60
+ production = grammar.productions[:$start][0]
61
+ rule = Rule.new(production, 0)
62
+ compute_whole_state(rule)
63
+ end
64
+
65
+ # Computes the entire initial state from the initial rule.
66
+ # It starts with a blank state, adds the initial rule to it, and
67
+ # then generates the closure for that state; it then computes
68
+ # the rest of the states in the grammar.
69
+ #
70
+ # @param rule [Rule] the initial rule.
71
+ # @return [State]
72
+ def compute_whole_state(rule)
73
+ state = State.new
74
+ state << rule
75
+ compute_closure(state)
76
+ states << state
77
+ compute_states
78
+ state
79
+ end
80
+
81
+ # Computes all states. Uses a fix point iteration to determine
82
+ # when no states have been added. Loops through every state and
83
+ # every rule, looking for rules that have an active nonterminal
84
+ # and computing the closure for said rule.
85
+ #
86
+ # @return [void]
87
+ # @see #compute_closure
88
+ def compute_states
89
+ fixed_point(states) do
90
+ states.dup.each do |state|
91
+ compute_gotos(state)
92
+ end
93
+ end
94
+ end
95
+
96
+ # Given a state, it does a fixed point iteration on the rules of
97
+ # the state that have an active nonterminal, and add the
98
+ # corresponding production rules to the state.
99
+ #
100
+ # @return [void]
101
+ def compute_closure(state)
102
+ fixed_point(state.rules) do
103
+ state.rules.select { |r| r.active.nonterminal? }.each do |rule|
104
+ grammar.productions[rule.active.name].each do |prod|
105
+ state << Rule.new(prod, 0)
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ def compute_gotos(state)
112
+ actives = state.rules.map(&:active).select(&:name)
113
+
114
+ actives.each do |active|
115
+ next if state.transitions[active.name]
116
+ rules = state.rules
117
+ .select { |r| r.active == active && r.succ? }
118
+ .map(&:succ).to_set
119
+ s = states.find { |st| rules.subset? st.rules } || begin
120
+ s = State.new << rules
121
+ compute_closure(s)
122
+ states << s
123
+ s
124
+ end
125
+
126
+ state.transitions[active.name] = s
127
+ end
128
+ end
129
+
130
+ private
131
+
132
+ # Changes the IDs of the states into a more friendly format.
133
+ #
134
+ # @return [void]
135
+ def redefine_state_ids
136
+ states.each_with_index do |state, i|
137
+ state.id = i
138
+ end
139
+ end
140
+
141
+ # Redefines all of the rule ids to make them more friendly.
142
+ # Every rule in every state is given a unique ID, reguardless if
143
+ # the rules are equivalent.
144
+ #
145
+ # @return [void]
146
+ def redefine_rule_ids
147
+ start = 0
148
+
149
+ states.each do |state|
150
+ state.rules.each do |rule|
151
+ rule.id = start
152
+ start += 1
153
+ end
154
+ end
155
+ end
156
+
157
+ # Begins a fixed point iteration on the given enumerable. It
158
+ # initializes the added elements to one; then, while the number
159
+ # of added elements is not zero, it yields and checks for added
160
+ # elements.
161
+ #
162
+ # @param enum [Enumerable]
163
+ # @yield for every iteration. Guarenteed to do so at least
164
+ # once.
165
+ # @return [void]
166
+ def fixed_point(enum)
167
+ added = 1
168
+
169
+ until added.zero?
170
+ added = enum.size
171
+ yield
172
+ added = enum.size - added
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end