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,150 +1,156 @@
1
- # encoding: utf-8
2
-
3
- module Antelope
4
- module Ace
5
- class Grammar
6
-
7
- # Manages the productions of the grammar.
8
- module Productions
9
-
10
- # Returns a hash of all of the productions. The result is
11
- # cached.
12
- #
13
- # @return [Hash<(Symbol, Array<Production>)>]
14
- def productions
15
- @_productions || generate_productions
16
- end
17
-
18
- # Returns all productions for all nonterminals, sorted by id.
19
- #
20
- # @return [Array<Production>]
21
- def all_productions
22
- productions.values.flatten.sort_by(&:id)
23
- end
24
-
25
- # Finds a token based on its corresponding symbol. First
26
- # checks the productions, to see if it's a nonterminal; then,
27
- # tries to find it in the terminals; otherwise, if the symbol
28
- # is `error`, it returns a {Token::Error}; if the symbol is
29
- # `nothing` or `ε`, it returns a {Token::Epsilon}; if it's
30
- # none of those, it raises an {UndefinedTokenError}.
31
- #
32
- # @raise [UndefinedTokenError] if the token doesn't exist.
33
- # @param value [String, Symbol, #intern] the token's symbol to
34
- # check.
35
- # @return [Token]
36
- def find_token(value)
37
- value = value.intern
38
-
39
- if productions.key?(value)
40
- typed_nonterminals.find { |term| term.name == value } ||
41
- Token::Nonterminal.new(value)
42
- elsif terminal = terminals.
43
- find { |term| term.name == value }
44
- terminal
45
- elsif value == :error
46
- Token::Error.new
47
- elsif [:nothing, ].include?(value)
48
- Token::Epsilon.new
49
- else
50
- raise UndefinedTokenError, "Could not find a token " \
51
- "named #{value.inspect}"
52
- end
53
- end
54
-
55
- private
56
-
57
- # Actually generates the productions. Uses the rules from the
58
- # compiler to construct the productions. Makes two loops over
59
- # the compiler's rules; the first to tell the grammar that the
60
- # nonterminal does exist, and the second to actually construct
61
- # the productions. The first loop is for {#find_token},
62
- # because otherwise it wouldn't be able to return a
63
- # nonterminal properly.
64
- #
65
- # @return [Hash<(Symbol, Array<Production>)>]
66
- def generate_productions
67
- @_productions = {}
68
-
69
- @compiler.rules.each do |rule|
70
- productions[rule[:label]] = []
71
- end.each_with_index do |rule, id|
72
- productions[rule[:label]] <<
73
- generate_production_for(rule, id)
74
- end
75
-
76
- productions[:$start] = [default_production]
77
-
78
- productions
79
- end
80
-
81
- # Generates a production for a given compiler rule. Converts
82
- # the tokens in the set to their {Token} counterparts,
83
- # and then sets the precedence for the production. If the
84
- # precedence declaration from the compiler rule is empty,
85
- # then it'll use the last terminal from the set to check for
86
- # precedence; otherwise, it'll use the precedence declaration.
87
- # This is to make sure that every production has a precedence
88
- # declaration.
89
- #
90
- # @param rule [Hash] the compiler's rule.
91
- # @param id [Numeric] the id for the production.
92
- # @return [Production]
93
- def generate_production_for(rule, id)
94
- left = Token::Nonterminal.new(rule[:label])
95
- items = rule[:set].map { |_| find_token(_[0]) }
96
- prec = if rule[:prec].empty?
97
- items.select(&:terminal?).last
98
- else
99
- rule[:prec].intern
100
- end
101
-
102
- prec = precedence_for(prec)
103
- left.type = type_for(rule[:label])
104
- left.id = rule[:label_id]
105
-
106
- rule[:set].each_with_index do |tok, i|
107
- items[i] = items[i].dup
108
- items[i].id = tok[1]
109
- end
110
-
111
- Production.new(left, items, rule[:block], prec, id + 1)
112
- end
113
-
114
- # Returns the defined type for the given token name.
115
- # Uses the `%type` directive to infer the corresponding types.
116
- #
117
- # @param token [Symbol] the token to check for
118
- # types.
119
- def type_for(token)
120
- token = find_token(token) unless token.is_a?(Token)
121
-
122
- case token
123
- when Token::Nonterminal
124
- token.type
125
- when Token::Terminal
126
- token.type
127
- when Token::Epsilon
128
- ""
129
- when Token::Error
130
- ""
131
- end
132
- end
133
-
134
- # Creates the default production for the grammar. The left
135
- # hand side of the production is the `:$start` symbol, with
136
- # the right hand side being the first rule's left-hand side
137
- # and the terminal `$`. This production is automagically
138
- # given the last precedence, and an id of 0.
139
- #
140
- # @return [Production]
141
- def default_production
142
- Production.new(Token::Nonterminal.new(:$start), [
143
- Token::Nonterminal.new(@compiler.rules.first[:label]),
144
- Token::Terminal.new(:$end)
145
- ], "", precedence.last, 0)
146
- end
147
- end
148
- end
149
- end
150
- end
1
+ # encoding: utf-8
2
+
3
+ module Antelope
4
+ module Ace
5
+ class Grammar
6
+
7
+ # Manages the productions of the grammar.
8
+ module Productions
9
+
10
+ # Returns a hash of all of the productions. The result is
11
+ # cached.
12
+ #
13
+ # @return [Hash<(Symbol, Array<Production>)>]
14
+ def productions
15
+ @_productions || generate_productions
16
+ end
17
+
18
+ # Returns all productions for all nonterminals, sorted by id.
19
+ #
20
+ # @return [Array<Production>]
21
+ def all_productions
22
+ productions.values.flatten.sort_by(&:id)
23
+ end
24
+
25
+ # Finds a token based on its corresponding symbol. First
26
+ # checks the productions, to see if it's a nonterminal; then,
27
+ # tries to find it in the terminals; otherwise, if the symbol
28
+ # is `error`, it returns a {Token::Error}; if the symbol is
29
+ # `nothing` or `ε`, it returns a {Token::Epsilon}; if it's
30
+ # none of those, it raises an {UndefinedTokenError}.
31
+ #
32
+ # @raise [UndefinedTokenError] if the token doesn't exist.
33
+ # @param value [String, Symbol, #intern] the token's symbol to
34
+ # check.
35
+ # @return [Token]
36
+ def find_token(value)
37
+ value = value.intern
38
+
39
+ if productions.key?(value)
40
+ typed_nonterminals.find { |term| term.name == value } ||
41
+ Token::Nonterminal.new(value)
42
+ elsif terminal = terminals.
43
+ find { |term| term.name == value }
44
+ terminal
45
+ elsif value == :error
46
+ Token::Error.new
47
+ elsif [:nothing, :ε, :"%empty"].include?(value)
48
+ Token::Epsilon.new
49
+ else
50
+ raise UndefinedTokenError, "Could not find a token " \
51
+ "named #{value.inspect}"
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ # Actually generates the productions. Uses the rules from the
58
+ # compiler to construct the productions. Makes two loops over
59
+ # the compiler's rules; the first to tell the grammar that the
60
+ # nonterminal does exist, and the second to actually construct
61
+ # the productions. The first loop is for {#find_token},
62
+ # because otherwise it wouldn't be able to return a
63
+ # nonterminal properly.
64
+ #
65
+ # @return [Hash<(Symbol, Array<Production>)>]
66
+ def generate_productions
67
+ @_productions = {}
68
+ index = 0
69
+
70
+ rules = @compiler.rules.each do |rule|
71
+ productions[rule[:label]] = []
72
+ end
73
+
74
+ while index < rules.size
75
+ rule = rules[index]
76
+ productions[rule[:label]] <<
77
+ generate_production_for(rule, index)
78
+ index += 1
79
+ end
80
+
81
+ productions[:$start] = [default_production]
82
+
83
+ productions
84
+ end
85
+
86
+ # Generates a production for a given compiler rule. Converts
87
+ # the tokens in the set to their {Token} counterparts,
88
+ # and then sets the precedence for the production. If the
89
+ # precedence declaration from the compiler rule is empty,
90
+ # then it'll use the last terminal from the set to check for
91
+ # precedence; otherwise, it'll use the precedence declaration.
92
+ # This is to make sure that every production has a precedence
93
+ # declaration.
94
+ #
95
+ # @param rule [Hash] the compiler's rule.
96
+ # @param id [Numeric] the id for the production.
97
+ # @return [Production]
98
+ def generate_production_for(rule, id)
99
+ left = Token::Nonterminal.new(rule[:label])
100
+ items = rule[:set].map { |_| find_token(_[0]) }
101
+ prec = if rule[:prec].empty?
102
+ items.select(&:terminal?).last
103
+ else
104
+ rule[:prec].intern
105
+ end
106
+
107
+ prec = precedence_for(prec)
108
+ left.type = type_for(rule[:label])
109
+ left.id = rule[:label_id]
110
+
111
+ rule[:set].each_with_index do |tok, i|
112
+ items[i] = items[i].dup
113
+ items[i].id = tok[1]
114
+ end
115
+ items.delete_if(&:epsilon?)
116
+
117
+ Production.new(left, items, rule[:block], prec, id + 1)
118
+ end
119
+
120
+ # Returns the defined type for the given token name.
121
+ # Uses the `%type` directive to infer the corresponding types.
122
+ #
123
+ # @param token [Symbol] the token to check for
124
+ # types.
125
+ def type_for(token)
126
+ token = find_token(token) unless token.is_a?(Token)
127
+
128
+ case token
129
+ when Token::Nonterminal
130
+ token.type
131
+ when Token::Terminal
132
+ token.type
133
+ when Token::Epsilon
134
+ ""
135
+ when Token::Error
136
+ ""
137
+ end
138
+ end
139
+
140
+ # Creates the default production for the grammar. The left
141
+ # hand side of the production is the `:$start` symbol, with
142
+ # the right hand side being the first rule's left-hand side
143
+ # and the terminal `$`. This production is automagically
144
+ # given the last precedence, and an id of 0.
145
+ #
146
+ # @return [Production]
147
+ def default_production
148
+ Production.new(Token::Nonterminal.new(:$start), [
149
+ Token::Nonterminal.new(@compiler.rules.first[:label]),
150
+ Token::Terminal.new(:$end)
151
+ ], "", precedence.last, 0)
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
@@ -1,66 +1,66 @@
1
- # encoding: utf-8
2
-
3
- module Antelope
4
- module Ace
5
- class Grammar
6
-
7
- # Manages a list of the symbols in the grammar.
8
- module Symbols
9
-
10
- # A list of all terminals in the grammar. Checks the compiler
11
- # options for terminals, and then returns an array of
12
- # terminals. Caches the result.
13
- #
14
- # @return [Array<Token::Terminal>]
15
- def terminals
16
- @_terminals ||= begin
17
- @compiler.options.fetch(:terminals, []).map do |v|
18
- Token::Terminal.new(*v)
19
- end
20
- end
21
- end
22
-
23
- # A list of all nonterminals in the grammar.
24
- #
25
- # @return [Array<Symbol>]
26
- # @see #productions
27
- def nonterminals
28
- @_nonterminals ||= productions.keys
29
- end
30
-
31
- # A list of all nonterminals, with types.
32
- #
33
- # @return [Array<Token::Nonterminal>>]
34
- def typed_nonterminals
35
- @_typed_nonterminals ||= begin
36
- typed = []
37
- compiler.options[:nonterminals].each do |data|
38
- data[1].each do |nonterm|
39
- typed << Token::Nonterminal.new(nonterm, data[0])
40
- end
41
- end
42
- typed
43
- end
44
- end
45
-
46
- # A list of all symbols in the grammar; includes both
47
- # terminals and nonterminals.
48
- #
49
- # @return [Array<Token::Terminal, Symbol>]
50
- # @see #terminals
51
- # @see #nonterminals
52
- def symbols
53
- @_symbols ||= terminals + nonterminals
54
- end
55
-
56
- # Checks to see if the grammar uses the `error` terminal
57
- # anywhere.
58
- #
59
- # @return [Boolean]
60
- def contains_error_token?
61
- all_productions.any? { |_| _.items.any?(&:error?) }
62
- end
63
- end
64
- end
65
- end
66
- end
1
+ # encoding: utf-8
2
+
3
+ module Antelope
4
+ module Ace
5
+ class Grammar
6
+
7
+ # Manages a list of the symbols in the grammar.
8
+ module Symbols
9
+
10
+ # A list of all terminals in the grammar. Checks the compiler
11
+ # options for terminals, and then returns an array of
12
+ # terminals. Caches the result.
13
+ #
14
+ # @return [Array<Token::Terminal>]
15
+ def terminals
16
+ @_terminals ||= begin
17
+ @compiler.options.fetch(:terminals) { [] }.map do |v|
18
+ Token::Terminal.new(*v)
19
+ end
20
+ end
21
+ end
22
+
23
+ # A list of all nonterminals in the grammar.
24
+ #
25
+ # @return [Array<Symbol>]
26
+ # @see #productions
27
+ def nonterminals
28
+ @_nonterminals ||= productions.keys
29
+ end
30
+
31
+ # A list of all nonterminals, with types.
32
+ #
33
+ # @return [Array<Token::Nonterminal>>]
34
+ def typed_nonterminals
35
+ @_typed_nonterminals ||= begin
36
+ typed = []
37
+ compiler.options[:nonterminals].each do |data|
38
+ data[1].each do |nonterm|
39
+ typed << Token::Nonterminal.new(nonterm, data[0])
40
+ end
41
+ end
42
+ typed
43
+ end
44
+ end
45
+
46
+ # A list of all symbols in the grammar; includes both
47
+ # terminals and nonterminals.
48
+ #
49
+ # @return [Array<Token::Terminal, Symbol>]
50
+ # @see #terminals
51
+ # @see #nonterminals
52
+ def symbols
53
+ @_symbols ||= terminals + nonterminals
54
+ end
55
+
56
+ # Checks to see if the grammar uses the `error` terminal
57
+ # anywhere.
58
+ #
59
+ # @return [Boolean]
60
+ def contains_error_token?
61
+ all_productions.any? { |_| _.items.any?(&:error?) }
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -1,69 +1,69 @@
1
- # encoding: utf-8
2
-
3
- require "hashie"
4
- require "antelope/ace/grammar/symbols"
5
- require "antelope/ace/grammar/productions"
6
- require "antelope/ace/grammar/precedences"
7
- require "antelope/ace/grammar/loading"
8
- require "antelope/ace/grammar/generation"
9
-
10
- module Antelope
11
- module Ace
12
-
13
- # Defines a grammar from an Ace file. This handles setting up
14
- # productions, loading from files, symbols, precedence, and
15
- # generation.
16
- class Grammar
17
-
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
69
- end
1
+ # encoding: utf-8
2
+
3
+ require "hashie"
4
+ require "antelope/ace/grammar/symbols"
5
+ require "antelope/ace/grammar/productions"
6
+ require "antelope/ace/grammar/precedences"
7
+ require "antelope/ace/grammar/loading"
8
+ require "antelope/ace/grammar/generation"
9
+
10
+ module Antelope
11
+ module Ace
12
+
13
+ # Defines a grammar from an Ace file. This handles setting up
14
+ # productions, loading from files, symbols, precedence, and
15
+ # generation.
16
+ class Grammar
17
+
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
69
+ end