antelope 0.2.0 → 0.2.2

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