antelope 0.3.2 → 0.4.0

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 (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,86 +1,86 @@
1
- # encoding: utf-8
2
-
3
- module Antelope
4
- module Generation
5
- class Constructor
6
- # Contains the methods to construct first sets for tokens.
7
- module First
8
- # Initialize.
9
- def initialize
10
- @firstifying = []
11
- super
12
- end
13
-
14
- # Constructs the first set for a given token. This is how
15
- # the method should behave:
16
- #
17
- # FIRST(ε) == [] # if ε is the epsilon token
18
- # FIRST(x) == [x] # if x is a terminal
19
- # FIRST(αβ) == if nullable?(α)
20
- # FIRST(α) U FIRST(β)
21
- # else
22
- # FIRST(α)
23
- # end
24
- # FIRST(A) == FIRST(a_1) U FIRST(a_2) U ... U FIRST(a_n)
25
- # # if A is a nonterminal and a_1, a_2, ..., a_3 are all
26
- # # of the right-hand sides of its productions.
27
- #
28
- # @param token [Grammar::Token, Array<Grammar::Token>]
29
- # @return [Set<Grammar::Token::Terminal>]
30
- # @see #first_array
31
- def first(token)
32
- case token
33
- when Grammar::Token::Nonterminal
34
- firstifying(token) do
35
- productions = grammar.productions[token.name]
36
- productions.map { |prod|
37
- first(prod[:items]) }.inject(Set.new, :+)
38
- end
39
- when Array
40
- first_array(token)
41
- when Grammar::Token::Epsilon
42
- Set.new
43
- when Grammar::Token::Terminal
44
- Set.new([token])
45
- else
46
- incorrect_argument! token, Grammar::Token, Array
47
- end
48
- end
49
-
50
- private
51
-
52
- # Determines the FIRST set of an array of tokens. First, it
53
- # removes any terminals we are finding the FIRST set for;
54
- # then, it determines which tokens we have to find the FIRST
55
- # sets for (since some tokens may be nullable). We then add
56
- # those sets to our set.
57
- #
58
- # @param tokens [Array<Grammar::Token>]
59
- # @return [Set<Grammar::Token>]
60
- def first_array(tokens)
61
- tokens.dup.delete_if { |_| @firstifying.include?(_) }.
62
- each_with_index.take_while do |token, i|
63
- if i.zero?
64
- true
65
- else
66
- nullable?(tokens[i - 1])
67
- end
68
- end.map(&:first).map { |_| first(_) }.inject(Set.new, :+)
69
- end
70
-
71
- # Helps keep track of the nonterminals we're finding FIRST
72
- # sets for. This helps prevent recursion.
73
- #
74
- # @param tok [Grammar::Token::Nonterminal]
75
- # @yield once.
76
- # @return [Set<Grammar::Token>]
77
- def firstifying(tok)
78
- @firstifying << tok
79
- out = yield
80
- @firstifying.delete tok
81
- out
82
- end
83
- end
84
- end
85
- end
86
- end
1
+ # encoding: utf-8
2
+
3
+ module Antelope
4
+ module Generation
5
+ class Constructor
6
+ # Contains the methods to construct first sets for tokens.
7
+ module First
8
+ # Initialize.
9
+ def initialize
10
+ @firstifying = []
11
+ super
12
+ end
13
+
14
+ # Constructs the first set for a given token. This is how
15
+ # the method should behave:
16
+ #
17
+ # FIRST(ε) == [] # if ε is the epsilon token
18
+ # FIRST(x) == [x] # if x is a terminal
19
+ # FIRST(αβ) == if nullable?(α)
20
+ # FIRST(α) U FIRST(β)
21
+ # else
22
+ # FIRST(α)
23
+ # end
24
+ # FIRST(A) == FIRST(a_1) U FIRST(a_2) U ... U FIRST(a_n)
25
+ # # if A is a nonterminal and a_1, a_2, ..., a_3 are all
26
+ # # of the right-hand sides of its productions.
27
+ #
28
+ # @param token [Grammar::Token, Array<Grammar::Token>]
29
+ # @return [Set<Grammar::Token::Terminal>]
30
+ # @see #first_array
31
+ def first(token)
32
+ case token
33
+ when Grammar::Token::Nonterminal
34
+ firstifying(token) do
35
+ productions = grammar.productions[token.name]
36
+ productions.map { |prod|
37
+ first(prod[:items]) }.inject(Set.new, :+)
38
+ end
39
+ when Array
40
+ first_array(token)
41
+ when Grammar::Token::Epsilon
42
+ Set.new
43
+ when Grammar::Token::Terminal
44
+ Set.new([token])
45
+ else
46
+ incorrect_argument! token, Grammar::Token, Array
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ # Determines the FIRST set of an array of tokens. First, it
53
+ # removes any terminals we are finding the FIRST set for;
54
+ # then, it determines which tokens we have to find the FIRST
55
+ # sets for (since some tokens may be nullable). We then add
56
+ # those sets to our set.
57
+ #
58
+ # @param tokens [Array<Grammar::Token>]
59
+ # @return [Set<Grammar::Token>]
60
+ def first_array(tokens)
61
+ tokens.dup.delete_if { |_| @firstifying.include?(_) }.
62
+ each_with_index.take_while do |token, i|
63
+ if i.zero?
64
+ true
65
+ else
66
+ nullable?(tokens[i - 1])
67
+ end
68
+ end.map(&:first).map { |_| first(_) }.inject(Set.new, :+)
69
+ end
70
+
71
+ # Helps keep track of the nonterminals we're finding FIRST
72
+ # sets for. This helps prevent recursion.
73
+ #
74
+ # @param tok [Grammar::Token::Nonterminal]
75
+ # @yield once.
76
+ # @return [Set<Grammar::Token>]
77
+ def firstifying(tok)
78
+ @firstifying << tok
79
+ out = yield
80
+ @firstifying.delete tok
81
+ out
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -1,105 +1,105 @@
1
- # encoding: utf-8
2
-
3
- module Antelope
4
- module Generation
5
- class Constructor
6
-
7
- # Contains the methods to find the FOLLOW sets of nonterminals.
8
- module Follow
9
-
10
- # Initialize.
11
- def initialize
12
- @follows = {}
13
- super
14
- end
15
-
16
- # Returns the FOLLOW set of the given token. If the given
17
- # token isn't a nonterminal, it raises an error. It then
18
- # generates the FOLLOW set for the given token, and then
19
- # caches it.
20
- #
21
- # @return [Set<Grammar::Token>]
22
- # @see Constructor#incorrect_argument!
23
- # @see #generate_follow_set
24
- def follow(token)
25
- unless token.is_a? Grammar::Token::Nonterminal
26
- incorrect_argument! token, Grammar::Token::Nonterminal
27
- end
28
-
29
- @follows.fetch(token) { generate_follow_set(token) }
30
- end
31
-
32
- private
33
-
34
- # Generates the FOLLOW set for the given token. It finds the
35
- # positions at which the token appears in the grammar, and
36
- # sees what could possibly follow it. For example, given the
37
- # following production:
38
- #
39
- # A -> aBz
40
- #
41
- # With `a` and `z` being any combination of terminals and
42
- # nonterminals, and we're trying to find the FOLLOW set of
43
- # `B` we add the FIRST set of `z` to the FOLLOW set of `B`:
44
- #
45
- # FOLLOW(B) = FOLLOW(B) ∪ FIRST(z)
46
- #
47
- # In the case that `B` is at the end of a production, like so:
48
- #
49
- # A -> aB
50
- #
51
- # or
52
- #
53
- # A -> aBw
54
- #
55
- # (with `w` being nullable) We also add the FOLLOW set of `A`
56
- # to `B`:
57
- #
58
- # FOLLOW(B) = FOLLOW(B) ∪ FOLLOW(A)
59
- #
60
- # In case this operation is potentially recursive, we make
61
- # sure to set the FOLLOW set of `B` to an empty set (since we
62
- # cache the result of a FOLLOW set, the empty set will be
63
- # returned).
64
- #
65
- # @param token [Grammar::Token::Nonterminal]
66
- # @return [Set<Grammar::Token>]
67
- # @see First#first
68
- # @see Nullable#nullable?
69
- def generate_follow_set(token)
70
- # Set it to the empty set so we don't end up recursing.
71
- @follows[token] = Set.new
72
- set = Set.new
73
-
74
- productions.each do |rule|
75
- items = rule.items
76
- i = 0
77
-
78
- # Find all of the positions within the rule that our token
79
- # occurs, and then increment that position by one.
80
- while i < items.size
81
- next i += 1 unless items[i] == token
82
- position = i.succ
83
-
84
- # Find the FIRST set of every item after our token, and
85
- # put that in our set.
86
- set.merge first(items[position..-1])
87
-
88
- # If we're at the end of the rule...
89
- if position == items.size || nullable?(items[position..-1])
90
- # Then add the FOLLOW set of the left-hand side to our
91
- # set.
92
- set.merge follow(rule.label)
93
- end
94
-
95
- i += 1
96
- end
97
- end
98
-
99
- # ReplGrammar the cached empty set with our filled set.
100
- @follows[token] = set
101
- end
102
- end
103
- end
104
- end
105
- end
1
+ # encoding: utf-8
2
+
3
+ module Antelope
4
+ module Generation
5
+ class Constructor
6
+
7
+ # Contains the methods to find the FOLLOW sets of nonterminals.
8
+ module Follow
9
+
10
+ # Initialize.
11
+ def initialize
12
+ @follows = {}
13
+ super
14
+ end
15
+
16
+ # Returns the FOLLOW set of the given token. If the given
17
+ # token isn't a nonterminal, it raises an error. It then
18
+ # generates the FOLLOW set for the given token, and then
19
+ # caches it.
20
+ #
21
+ # @return [Set<Grammar::Token>]
22
+ # @see Constructor#incorrect_argument!
23
+ # @see #generate_follow_set
24
+ def follow(token)
25
+ unless token.is_a? Grammar::Token::Nonterminal
26
+ incorrect_argument! token, Grammar::Token::Nonterminal
27
+ end
28
+
29
+ @follows.fetch(token) { generate_follow_set(token) }
30
+ end
31
+
32
+ private
33
+
34
+ # Generates the FOLLOW set for the given token. It finds the
35
+ # positions at which the token appears in the grammar, and
36
+ # sees what could possibly follow it. For example, given the
37
+ # following production:
38
+ #
39
+ # A -> aBz
40
+ #
41
+ # With `a` and `z` being any combination of terminals and
42
+ # nonterminals, and we're trying to find the FOLLOW set of
43
+ # `B` we add the FIRST set of `z` to the FOLLOW set of `B`:
44
+ #
45
+ # FOLLOW(B) = FOLLOW(B) ∪ FIRST(z)
46
+ #
47
+ # In the case that `B` is at the end of a production, like so:
48
+ #
49
+ # A -> aB
50
+ #
51
+ # or
52
+ #
53
+ # A -> aBw
54
+ #
55
+ # (with `w` being nullable) We also add the FOLLOW set of `A`
56
+ # to `B`:
57
+ #
58
+ # FOLLOW(B) = FOLLOW(B) ∪ FOLLOW(A)
59
+ #
60
+ # In case this operation is potentially recursive, we make
61
+ # sure to set the FOLLOW set of `B` to an empty set (since we
62
+ # cache the result of a FOLLOW set, the empty set will be
63
+ # returned).
64
+ #
65
+ # @param token [Grammar::Token::Nonterminal]
66
+ # @return [Set<Grammar::Token>]
67
+ # @see First#first
68
+ # @see Nullable#nullable?
69
+ def generate_follow_set(token)
70
+ # Set it to the empty set so we don't end up recursing.
71
+ @follows[token] = Set.new
72
+ set = Set.new
73
+
74
+ productions.each do |rule|
75
+ items = rule.items
76
+ i = 0
77
+
78
+ # Find all of the positions within the rule that our token
79
+ # occurs, and then increment that position by one.
80
+ while i < items.size
81
+ next i += 1 unless items[i] == token
82
+ position = i.succ
83
+
84
+ # Find the FIRST set of every item after our token, and
85
+ # put that in our set.
86
+ set.merge first(items[position..-1])
87
+
88
+ # If we're at the end of the rule...
89
+ if position == items.size || nullable?(items[position..-1])
90
+ # Then add the FOLLOW set of the left-hand side to our
91
+ # set.
92
+ set.merge follow(rule.label)
93
+ end
94
+
95
+ i += 1
96
+ end
97
+ end
98
+
99
+ # ReplGrammar the cached empty set with our filled set.
100
+ @follows[token] = set
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -1,64 +1,64 @@
1
- # encoding: utf-8
2
-
3
- module Antelope
4
- module Generation
5
- class Constructor
6
-
7
- # Contains the methods to determine if an object is nullable.
8
- module Nullable
9
-
10
- # Initialize.
11
- def initialize
12
- @nullifying = Set.new
13
- end
14
-
15
- # Determine if a given token is nullable. This is how the
16
- # method should behave:
17
- #
18
- # nullable?(ϵ) == true # if ϵ is the epsilon token
19
- # nullable?(x) == false # if x is a terminal
20
- # nullable?(αβ) == nullable?(α) && nullable?(β)
21
- # nullable?(A) == nullable?(a_1) || nullable?(a_2) || ... nullable?(a_n)
22
- # # if A is a nonterminal and a_1, a_2, ..., a_n are all
23
- # # of the right-hand sides of its productions
24
- #
25
- # @param token [Grammar::Token, Array<Grammar::Token>] the token to
26
- # check.
27
- # @return [Boolean] if the token can reduce to ϵ.
28
- def nullable?(token)
29
- case token
30
- when Grammar::Token::Nonterminal
31
- nullifying(token) do
32
- productions = grammar.productions[token.name]
33
- !!productions.any? { |prod| nullable?(prod[:items]) }
34
- end
35
- when Array
36
- token.dup.delete_if { |tok|
37
- @nullifying.include?(tok) }.all? { |tok| nullable?(tok) }
38
- when Grammar::Token::Epsilon
39
- true
40
- when Grammar::Token::Terminal
41
- false
42
- else
43
- incorrect_argument! token, Grammar::Token, Array
44
- end
45
- end
46
-
47
- private
48
-
49
- # Helps keep track of the nonterminals we're checking for
50
- # nullability. This helps prevent recursion.
51
- #
52
- # @param tok [Grammar::Token::Nonterminal]
53
- # @yield once.
54
- # @return [Boolean]
55
- def nullifying(tok)
56
- @nullifying << tok
57
- out = yield
58
- @nullifying.delete tok
59
- out
60
- end
61
- end
62
- end
63
- end
64
- end
1
+ # encoding: utf-8
2
+
3
+ module Antelope
4
+ module Generation
5
+ class Constructor
6
+
7
+ # Contains the methods to determine if an object is nullable.
8
+ module Nullable
9
+
10
+ # Initialize.
11
+ def initialize
12
+ @nullifying = Set.new
13
+ end
14
+
15
+ # Determine if a given token is nullable. This is how the
16
+ # method should behave:
17
+ #
18
+ # nullable?(ϵ) == true # if ϵ is the epsilon token
19
+ # nullable?(x) == false # if x is a terminal
20
+ # nullable?(αβ) == nullable?(α) && nullable?(β)
21
+ # nullable?(A) == nullable?(a_1) || nullable?(a_2) || ... nullable?(a_n)
22
+ # # if A is a nonterminal and a_1, a_2, ..., a_n are all
23
+ # # of the right-hand sides of its productions
24
+ #
25
+ # @param token [Grammar::Token, Array<Grammar::Token>] the token to
26
+ # check.
27
+ # @return [Boolean] if the token can reduce to ϵ.
28
+ def nullable?(token)
29
+ case token
30
+ when Grammar::Token::Nonterminal
31
+ nullifying(token) do
32
+ productions = grammar.productions[token.name]
33
+ !!productions.any? { |prod| nullable?(prod[:items]) }
34
+ end
35
+ when Array
36
+ token.dup.delete_if { |tok|
37
+ @nullifying.include?(tok) }.all? { |tok| nullable?(tok) }
38
+ when Grammar::Token::Epsilon
39
+ true
40
+ when Grammar::Token::Terminal
41
+ false
42
+ else
43
+ incorrect_argument! token, Grammar::Token, Array
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ # Helps keep track of the nonterminals we're checking for
50
+ # nullability. This helps prevent recursion.
51
+ #
52
+ # @param tok [Grammar::Token::Nonterminal]
53
+ # @yield once.
54
+ # @return [Boolean]
55
+ def nullifying(tok)
56
+ @nullifying << tok
57
+ out = yield
58
+ @nullifying.delete tok
59
+ out
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end