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,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