antelope 0.3.2 → 0.4.0

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