antelope 0.2.0 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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