antelope 0.2.4 → 0.3.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +11 -0
- data/bin/antelope +3 -3
- data/examples/{example.err → example.ace.err} +9 -9
- data/examples/{example.inf → example.ace.inf} +57 -9
- data/examples/example.ate +70 -0
- data/examples/example.ate.err +192 -0
- data/examples/example.ate.inf +432 -0
- data/lib/antelope/ace/compiler.rb +4 -4
- data/lib/antelope/ace/errors.rb +0 -18
- data/lib/antelope/ace.rb +6 -12
- data/lib/antelope/cli.rb +1 -1
- data/lib/antelope/dsl/compiler.rb +117 -0
- data/lib/antelope/dsl/contexts/base.rb +29 -0
- data/lib/antelope/dsl/contexts/main.rb +63 -0
- data/lib/antelope/dsl/contexts/match.rb +24 -0
- data/lib/antelope/dsl/contexts/precedence.rb +20 -0
- data/lib/antelope/dsl/contexts/production.rb +24 -0
- data/lib/antelope/dsl/contexts/terminal.rb +28 -0
- data/lib/antelope/dsl/contexts.rb +16 -0
- data/lib/antelope/dsl.rb +9 -0
- data/lib/antelope/errors.rb +18 -1
- data/lib/antelope/generation/constructor/first.rb +10 -12
- data/lib/antelope/generation/constructor/follow.rb +6 -6
- data/lib/antelope/generation/constructor/nullable.rb +6 -6
- data/lib/antelope/generation/constructor.rb +4 -4
- data/lib/antelope/generation/recognizer/rule.rb +17 -17
- data/lib/antelope/generation/recognizer/state.rb +9 -10
- data/lib/antelope/generation/recognizer.rb +8 -11
- data/lib/antelope/generation/tableizer.rb +2 -2
- data/lib/antelope/generator/base.rb +7 -7
- data/lib/antelope/generator/ruby.rb +1 -1
- data/lib/antelope/grammar/generation.rb +77 -0
- data/lib/antelope/grammar/loading.rb +84 -0
- data/lib/antelope/{ace → grammar}/precedence.rb +2 -4
- data/lib/antelope/grammar/precedences.rb +64 -0
- data/lib/antelope/{ace → grammar}/production.rb +11 -12
- data/lib/antelope/grammar/productions.rb +154 -0
- data/lib/antelope/grammar/symbols.rb +64 -0
- data/lib/antelope/{ace → grammar}/token/epsilon.rb +1 -2
- data/lib/antelope/{ace → grammar}/token/error.rb +1 -3
- data/lib/antelope/{ace → grammar}/token/nonterminal.rb +1 -3
- data/lib/antelope/{ace → grammar}/token/terminal.rb +1 -3
- data/lib/antelope/{ace → grammar}/token.rb +12 -15
- data/lib/antelope/grammar.rb +68 -0
- data/lib/antelope/version.rb +1 -1
- data/lib/antelope.rb +12 -6
- data/spec/antelope/ace/compiler_spec.rb +6 -6
- data/spec/antelope/ace/scanner_spec.rb +7 -7
- data/spec/antelope/generation/constructor_spec.rb +131 -0
- data/spec/support/grammar_helper.rb +2 -3
- metadata +32 -19
- data/lib/antelope/ace/grammar/generation.rb +0 -80
- data/lib/antelope/ace/grammar/loading.rb +0 -53
- data/lib/antelope/ace/grammar/precedences.rb +0 -68
- data/lib/antelope/ace/grammar/productions.rb +0 -156
- data/lib/antelope/ace/grammar/symbols.rb +0 -66
- data/lib/antelope/ace/grammar.rb +0 -69
- data/spec/antelope/constructor_spec.rb +0 -133
@@ -0,0 +1,63 @@
|
|
1
|
+
module Antelope
|
2
|
+
module DSL
|
3
|
+
module Contexts
|
4
|
+
# The main context of the Antelope DSL.
|
5
|
+
class Main < Base
|
6
|
+
def define(pass)
|
7
|
+
pass.each do |key, value|
|
8
|
+
case value
|
9
|
+
when Array
|
10
|
+
@defines[key] = value
|
11
|
+
else
|
12
|
+
@defines[key] = [value]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def terminals(&block)
|
18
|
+
@terminals.merge! context(Terminal, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def precedences(&block)
|
22
|
+
@precedences = context(Precedence, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def productions(&block)
|
26
|
+
@productions = context(Production, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def template(template)
|
30
|
+
case template
|
31
|
+
when Hash
|
32
|
+
@templates.merge(template)
|
33
|
+
when String
|
34
|
+
@templates[:default] = template
|
35
|
+
else
|
36
|
+
raise ArgumentError, "Unexpected #{template.class}, " \
|
37
|
+
"expected String or Hash"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def before_call
|
44
|
+
@defines = {}
|
45
|
+
@templates = {}
|
46
|
+
@terminals = {}
|
47
|
+
@precedences = []
|
48
|
+
@productions = []
|
49
|
+
end
|
50
|
+
|
51
|
+
def data
|
52
|
+
{
|
53
|
+
defines: @defines,
|
54
|
+
templates: @templates,
|
55
|
+
terminals: @terminals,
|
56
|
+
precedences: @precedences,
|
57
|
+
productions: @productions
|
58
|
+
}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Antelope
|
2
|
+
module DSL
|
3
|
+
module Contexts
|
4
|
+
class Match < Base
|
5
|
+
def match(options)
|
6
|
+
body = options.fetch(:body)
|
7
|
+
action = options.fetch(:action)
|
8
|
+
prec = options.fetch(:prec, '')
|
9
|
+
|
10
|
+
@matches << { body: body, action: "{#{action}}", prec: prec }
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
attr_reader :matches
|
16
|
+
alias_method :data, :matches
|
17
|
+
|
18
|
+
def before_call
|
19
|
+
@matches = []
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Antelope
|
2
|
+
module DSL
|
3
|
+
module Contexts
|
4
|
+
class Precedence < Base
|
5
|
+
def precedence(type, contents)
|
6
|
+
@precedences << [type].concat(contents)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
attr_reader :precedences
|
12
|
+
alias_method :data, :precedences
|
13
|
+
|
14
|
+
def before_call
|
15
|
+
@precedences = []
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Antelope
|
2
|
+
module DSL
|
3
|
+
module Contexts
|
4
|
+
class Production < Base
|
5
|
+
def production(name, &block)
|
6
|
+
@productions[name].concat(context(Match, &block))
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
attr_reader :productions
|
12
|
+
alias_method :data, :productions
|
13
|
+
|
14
|
+
def before_call
|
15
|
+
@productions = Hash.new { |h, k| h[k] = [] }
|
16
|
+
end
|
17
|
+
|
18
|
+
def data
|
19
|
+
@productions
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Antelope
|
2
|
+
module DSL
|
3
|
+
module Contexts
|
4
|
+
class Terminal < Base
|
5
|
+
def terminal(map, value = true)
|
6
|
+
case map
|
7
|
+
when Hash
|
8
|
+
@terminals.merge!(map)
|
9
|
+
when Symbol, String
|
10
|
+
@terminals[map] = value
|
11
|
+
else
|
12
|
+
raise ArgumentError, "Unexpected #{map.class}, expected " \
|
13
|
+
"Hash or Symbol"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :terminals
|
20
|
+
alias_method :data, :terminals
|
21
|
+
|
22
|
+
def before_call
|
23
|
+
@terminals = {}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'antelope/dsl/contexts/base'
|
4
|
+
require 'antelope/dsl/contexts/main'
|
5
|
+
require 'antelope/dsl/contexts/match'
|
6
|
+
require 'antelope/dsl/contexts/precedence'
|
7
|
+
require 'antelope/dsl/contexts/production'
|
8
|
+
require 'antelope/dsl/contexts/terminal'
|
9
|
+
|
10
|
+
module Antelope
|
11
|
+
module DSL
|
12
|
+
# The contexts implemented within a DSL.
|
13
|
+
module Contexts
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/antelope/dsl.rb
ADDED
data/lib/antelope/errors.rb
CHANGED
@@ -1,8 +1,25 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
module Antelope
|
4
|
-
|
5
4
|
# Every error in antelope inherits this error class.
|
6
5
|
class Error < StandardError
|
7
6
|
end
|
7
|
+
|
8
|
+
# This is used primarily in the {Grammar}; if a rule references a
|
9
|
+
# token (a nonterminal or a terminal) that was not previously
|
10
|
+
# defined, this is raised.
|
11
|
+
class UndefinedTokenError < Error
|
12
|
+
end
|
13
|
+
|
14
|
+
# Used primarily in the {Compiler}, this is raised when the
|
15
|
+
# version requirement of the Ace file doesn't match the running
|
16
|
+
# version of Ace.
|
17
|
+
class IncompatibleVersionError < Error
|
18
|
+
end
|
19
|
+
|
20
|
+
# Primarily used in the {Grammar} (specifically
|
21
|
+
# {Grammar::Generation}), if the grammar could not determine the
|
22
|
+
# generator to use for the generation, it raises this.
|
23
|
+
class NoTypeError < Error
|
24
|
+
end
|
8
25
|
end
|
@@ -3,10 +3,8 @@
|
|
3
3
|
module Antelope
|
4
4
|
module Generation
|
5
5
|
class Constructor
|
6
|
-
|
7
6
|
# Contains the methods to construct first sets for tokens.
|
8
7
|
module First
|
9
|
-
|
10
8
|
# Initialize.
|
11
9
|
def initialize
|
12
10
|
@firstifying = []
|
@@ -27,12 +25,12 @@ module Antelope
|
|
27
25
|
# # if A is a nonterminal and a_1, a_2, ..., a_3 are all
|
28
26
|
# # of the right-hand sides of its productions.
|
29
27
|
#
|
30
|
-
# @param token [
|
31
|
-
# @return [Set<
|
28
|
+
# @param token [Grammar::Token, Array<Grammar::Token>]
|
29
|
+
# @return [Set<Grammar::Token::Terminal>]
|
32
30
|
# @see #first_array
|
33
31
|
def first(token)
|
34
32
|
case token
|
35
|
-
when
|
33
|
+
when Grammar::Token::Nonterminal
|
36
34
|
firstifying(token) do
|
37
35
|
productions = grammar.productions[token.name]
|
38
36
|
productions.map { |prod|
|
@@ -40,12 +38,12 @@ module Antelope
|
|
40
38
|
end
|
41
39
|
when Array
|
42
40
|
first_array(token)
|
43
|
-
when
|
41
|
+
when Grammar::Token::Epsilon
|
44
42
|
Set.new
|
45
|
-
when
|
43
|
+
when Grammar::Token::Terminal
|
46
44
|
Set.new([token])
|
47
45
|
else
|
48
|
-
incorrect_argument! token,
|
46
|
+
incorrect_argument! token, Grammar::Token, Array
|
49
47
|
end
|
50
48
|
end
|
51
49
|
|
@@ -57,8 +55,8 @@ module Antelope
|
|
57
55
|
# sets for (since some tokens may be nullable). We then add
|
58
56
|
# those sets to our set.
|
59
57
|
#
|
60
|
-
# @param tokens [Array<
|
61
|
-
# @return [Set<
|
58
|
+
# @param tokens [Array<Grammar::Token>]
|
59
|
+
# @return [Set<Grammar::Token>]
|
62
60
|
def first_array(tokens)
|
63
61
|
tokens.dup.delete_if { |_| @firstifying.include?(_) }.
|
64
62
|
each_with_index.take_while do |token, i|
|
@@ -73,9 +71,9 @@ module Antelope
|
|
73
71
|
# Helps keep track of the nonterminals we're finding FIRST
|
74
72
|
# sets for. This helps prevent recursion.
|
75
73
|
#
|
76
|
-
# @param tok [
|
74
|
+
# @param tok [Grammar::Token::Nonterminal]
|
77
75
|
# @yield once.
|
78
|
-
# @return [Set<
|
76
|
+
# @return [Set<Grammar::Token>]
|
79
77
|
def firstifying(tok)
|
80
78
|
@firstifying << tok
|
81
79
|
out = yield
|
@@ -18,12 +18,12 @@ module Antelope
|
|
18
18
|
# generates the FOLLOW set for the given token, and then
|
19
19
|
# caches it.
|
20
20
|
#
|
21
|
-
# @return [Set<
|
21
|
+
# @return [Set<Grammar::Token>]
|
22
22
|
# @see Constructor#incorrect_argument!
|
23
23
|
# @see #generate_follow_set
|
24
24
|
def follow(token)
|
25
|
-
unless token.is_a?
|
26
|
-
incorrect_argument! token,
|
25
|
+
unless token.is_a? Grammar::Token::Nonterminal
|
26
|
+
incorrect_argument! token, Grammar::Token::Nonterminal
|
27
27
|
end
|
28
28
|
|
29
29
|
@follows.fetch(token) { generate_follow_set(token) }
|
@@ -62,8 +62,8 @@ module Antelope
|
|
62
62
|
# cache the result of a FOLLOW set, the empty set will be
|
63
63
|
# returned).
|
64
64
|
#
|
65
|
-
# @param token [
|
66
|
-
# @return [Set<
|
65
|
+
# @param token [Grammar::Token::Nonterminal]
|
66
|
+
# @return [Set<Grammar::Token>]
|
67
67
|
# @see First#first
|
68
68
|
# @see Nullable#nullable?
|
69
69
|
def generate_follow_set(token)
|
@@ -96,7 +96,7 @@ module Antelope
|
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
|
-
#
|
99
|
+
# ReplGrammar the cached empty set with our filled set.
|
100
100
|
@follows[token] = set
|
101
101
|
end
|
102
102
|
end
|
@@ -22,12 +22,12 @@ module Antelope
|
|
22
22
|
# # if A is a nonterminal and a_1, a_2, ..., a_n are all
|
23
23
|
# # of the right-hand sides of its productions
|
24
24
|
#
|
25
|
-
# @param token [
|
25
|
+
# @param token [Grammar::Token, Array<Grammar::Token>] the token to
|
26
26
|
# check.
|
27
27
|
# @return [Boolean] if the token can reduce to ϵ.
|
28
28
|
def nullable?(token)
|
29
29
|
case token
|
30
|
-
when
|
30
|
+
when Grammar::Token::Nonterminal
|
31
31
|
nullifying(token) do
|
32
32
|
productions = grammar.productions[token.name]
|
33
33
|
!!productions.any? { |prod| nullable?(prod[:items]) }
|
@@ -35,12 +35,12 @@ module Antelope
|
|
35
35
|
when Array
|
36
36
|
token.dup.delete_if { |tok|
|
37
37
|
@nullifying.include?(tok) }.all? { |tok| nullable?(tok) }
|
38
|
-
when
|
38
|
+
when Grammar::Token::Epsilon
|
39
39
|
true
|
40
|
-
when
|
40
|
+
when Grammar::Token::Terminal
|
41
41
|
false
|
42
42
|
else
|
43
|
-
incorrect_argument! token,
|
43
|
+
incorrect_argument! token, Grammar::Token, Array
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
@@ -49,7 +49,7 @@ module Antelope
|
|
49
49
|
# Helps keep track of the nonterminals we're checking for
|
50
50
|
# nullability. This helps prevent recursion.
|
51
51
|
#
|
52
|
-
# @param tok [
|
52
|
+
# @param tok [Grammar::Token::Nonterminal]
|
53
53
|
# @yield once.
|
54
54
|
# @return [Boolean]
|
55
55
|
def nullifying(tok)
|
@@ -18,17 +18,17 @@ module Antelope
|
|
18
18
|
|
19
19
|
# The grammar.
|
20
20
|
#
|
21
|
-
# @return [
|
21
|
+
# @return [Grammar::Grammar]
|
22
22
|
attr_reader :grammar
|
23
23
|
|
24
24
|
# The augmented productions generated by the constructor.
|
25
25
|
#
|
26
|
-
# @return [Set<
|
26
|
+
# @return [Set<Grammar::Production>]
|
27
27
|
attr_reader :productions
|
28
28
|
|
29
29
|
# Initialize.
|
30
30
|
#
|
31
|
-
# @param grammar [
|
31
|
+
# @param grammar [Grammar::Grammar] the grammar.
|
32
32
|
def initialize(grammar)
|
33
33
|
@productions = Set.new
|
34
34
|
@grammar = grammar
|
@@ -120,7 +120,7 @@ module Antelope
|
|
120
120
|
private
|
121
121
|
|
122
122
|
def incorrect_argument!(arg, *types)
|
123
|
-
raise ArgumentError, "Expected one of #{types.join(
|
123
|
+
raise ArgumentError, "Expected one of #{types.join(', ')}, got #{arg.class}"
|
124
124
|
end
|
125
125
|
end
|
126
126
|
end
|
@@ -13,12 +13,12 @@ module Antelope
|
|
13
13
|
|
14
14
|
# The left-hand side of the rule.
|
15
15
|
#
|
16
|
-
# @return [
|
16
|
+
# @return [Grammar::Token::Nonterminal]
|
17
17
|
attr_reader :left
|
18
18
|
|
19
19
|
# The right-hand side of the rule.
|
20
20
|
#
|
21
|
-
# @return [Array<
|
21
|
+
# @return [Array<Grammar::Token>]
|
22
22
|
attr_reader :right
|
23
23
|
|
24
24
|
# The current position inside of the rule.
|
@@ -28,7 +28,7 @@ module Antelope
|
|
28
28
|
|
29
29
|
# The block to be executed on production match.
|
30
30
|
#
|
31
|
-
# @deprecated Use {
|
31
|
+
# @deprecated Use {Grammar::Production#block} instead.
|
32
32
|
# @return [String]
|
33
33
|
attr_reader :block
|
34
34
|
|
@@ -47,19 +47,19 @@ module Antelope
|
|
47
47
|
|
48
48
|
# The precedence for this rule.
|
49
49
|
#
|
50
|
-
# @return [
|
50
|
+
# @return [Grammar::Precedence]
|
51
51
|
attr_accessor :precedence
|
52
52
|
|
53
53
|
# The associated production.
|
54
54
|
#
|
55
|
-
# @return [
|
55
|
+
# @return [Grammar::Production]
|
56
56
|
attr_reader :production
|
57
57
|
|
58
58
|
include Comparable
|
59
59
|
|
60
60
|
# Initialize the rule.
|
61
61
|
#
|
62
|
-
# @param production [
|
62
|
+
# @param production [Grammar::Production] the production
|
63
63
|
# that this rule is based off of.
|
64
64
|
# @param position [Numeric] the position that this rule is in
|
65
65
|
# the production.
|
@@ -71,7 +71,7 @@ module Antelope
|
|
71
71
|
@precedence = production.prec
|
72
72
|
@production = production
|
73
73
|
@block = production.block
|
74
|
-
@id =
|
74
|
+
@id = format('%10x', object_id)
|
75
75
|
|
76
76
|
if inherited
|
77
77
|
@left, @right = inherited
|
@@ -85,7 +85,7 @@ module Antelope
|
|
85
85
|
# @return [String]
|
86
86
|
def inspect
|
87
87
|
"#<#{self.class} id=#{id} left=#{left} " \
|
88
|
-
"right=[#{right.join(
|
88
|
+
"right=[#{right.join(' ')}] position=#{position}>"
|
89
89
|
end
|
90
90
|
|
91
91
|
# Give a nicer representation of the rule as a string. Shows
|
@@ -97,16 +97,16 @@ module Antelope
|
|
97
97
|
# @return [String]
|
98
98
|
def to_s(dot = true)
|
99
99
|
"#{id}/#{precedence.type.to_s[0]}#{precedence.level}: " \
|
100
|
-
"#{left} → #{right[0, position].join(
|
101
|
-
"#{
|
100
|
+
"#{left} → #{right[0, position].join(' ')}" \
|
101
|
+
"#{' • ' if dot}#{right[position..-1].join(' ')}"
|
102
102
|
end
|
103
103
|
|
104
104
|
# Returns the active token. If there is no active token, it
|
105
|
-
# returns a blank {
|
105
|
+
# returns a blank {Grammar::Token}.
|
106
106
|
#
|
107
|
-
# @return [
|
107
|
+
# @return [Grammar::Token]
|
108
108
|
def active
|
109
|
-
right[position]
|
109
|
+
right[position] || Grammar::Token.new(nil)
|
110
110
|
end
|
111
111
|
|
112
112
|
# Creates the rule after this one by incrementing the position
|
@@ -174,9 +174,9 @@ module Antelope
|
|
174
174
|
# @return [Numeric]
|
175
175
|
def ===(other)
|
176
176
|
if other.is_a? Rule
|
177
|
-
left === other.left
|
178
|
-
right.each_with_index
|
179
|
-
all? { |e, i| e === other.right[i] }
|
177
|
+
left === other.left && right.size == other.right.size &&
|
178
|
+
right.each_with_index
|
179
|
+
.all? { |e, i| e === other.right[i] }
|
180
180
|
else
|
181
181
|
super
|
182
182
|
end
|
@@ -206,7 +206,7 @@ module Antelope
|
|
206
206
|
# @note This is not intended for use. It is only defined to
|
207
207
|
# make equality checking easier, and to create a hash.
|
208
208
|
# @private
|
209
|
-
# @return [Array<(
|
209
|
+
# @return [Array<(Grammar::Token::Nonterminal, Array<Grammar::Token>, Numeric)>]
|
210
210
|
def to_a
|
211
211
|
@_array ||= [left, right, position]
|
212
212
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'forwardable'
|
4
|
+
require 'securerandom'
|
5
5
|
|
6
6
|
module Antelope
|
7
7
|
module Generation
|
@@ -37,7 +37,7 @@ module Antelope
|
|
37
37
|
def initialize
|
38
38
|
@rules = Set.new
|
39
39
|
@transitions = {}
|
40
|
-
@id =
|
40
|
+
@id = format('%10x', object_id)
|
41
41
|
end
|
42
42
|
|
43
43
|
# Gives a nice string representation of the state.
|
@@ -45,8 +45,8 @@ module Antelope
|
|
45
45
|
# @return [String]
|
46
46
|
def inspect
|
47
47
|
"#<#{self.class} id=#{id} " \
|
48
|
-
"transitions=[#{transitions.keys.join(
|
49
|
-
"rules=[{#{rules.to_a.join(
|
48
|
+
"transitions=[#{transitions.keys.join(', ')}] " \
|
49
|
+
"rules=[{#{rules.to_a.join('} {')}}]>"
|
50
50
|
end
|
51
51
|
|
52
52
|
# Merges another state with this state. It copies all of the
|
@@ -61,7 +61,7 @@ module Antelope
|
|
61
61
|
"got #{other.class}" unless other.is_a? State
|
62
62
|
|
63
63
|
self << other
|
64
|
-
|
64
|
+
transitions.merge! other.transitions
|
65
65
|
|
66
66
|
self
|
67
67
|
end
|
@@ -90,7 +90,7 @@ module Antelope
|
|
90
90
|
when State
|
91
91
|
rule.rules.map(&:clone).each { |r| self << r }
|
92
92
|
when Rule
|
93
|
-
rules << rule
|
93
|
+
rules << rule
|
94
94
|
when Array, Set
|
95
95
|
rule.each do |part|
|
96
96
|
self << part
|
@@ -120,10 +120,9 @@ module Antelope
|
|
120
120
|
other_rules = other.rules.to_a
|
121
121
|
other.transitions == transitions &&
|
122
122
|
rules.size == other_rules.size &&
|
123
|
-
rules.each_with_index
|
124
|
-
all? { |rule, i| rule === other_rules[i] }
|
123
|
+
rules.each_with_index
|
124
|
+
.all? { |rule, i| rule === other_rules[i] }
|
125
125
|
end
|
126
|
-
|
127
126
|
end
|
128
127
|
end
|
129
128
|
end
|
@@ -1,16 +1,14 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'antelope/generation/recognizer/rule'
|
4
|
+
require 'antelope/generation/recognizer/state'
|
5
5
|
|
6
6
|
module Antelope
|
7
7
|
module Generation
|
8
|
-
|
9
8
|
# Recognizes all of the states in the grammar.
|
10
9
|
#
|
11
10
|
# @see http://redjazz96.tumblr.com/post/88446352960
|
12
11
|
class Recognizer
|
13
|
-
|
14
12
|
# A list of all of the states in the grammar.
|
15
13
|
#
|
16
14
|
# @return [Set<State>]
|
@@ -24,12 +22,12 @@ module Antelope
|
|
24
22
|
|
25
23
|
# The grammar that the recognizer is running off of.
|
26
24
|
#
|
27
|
-
# @return [
|
25
|
+
# @return [Grammar]
|
28
26
|
attr_reader :grammar
|
29
27
|
|
30
28
|
# Initialize the recognizer.
|
31
29
|
#
|
32
|
-
# @param grammar [
|
30
|
+
# @param grammar [Grammar]
|
33
31
|
def initialize(grammar)
|
34
32
|
@grammar = grammar
|
35
33
|
@states = Set.new
|
@@ -102,7 +100,7 @@ module Antelope
|
|
102
100
|
# @return [void]
|
103
101
|
def compute_closure(state)
|
104
102
|
fixed_point(state.rules) do
|
105
|
-
state.rules.select { |
|
103
|
+
state.rules.select { |r| r.active.nonterminal? }.each do |rule|
|
106
104
|
grammar.productions[rule.active.name].each do |prod|
|
107
105
|
state << Rule.new(prod, 0)
|
108
106
|
end
|
@@ -115,9 +113,9 @@ module Antelope
|
|
115
113
|
|
116
114
|
actives.each do |active|
|
117
115
|
next if state.transitions[active.name]
|
118
|
-
rules = state.rules
|
119
|
-
|
120
|
-
|
116
|
+
rules = state.rules
|
117
|
+
.select { |r| r.active == active && r.succ? }
|
118
|
+
.map(&:succ).to_set
|
121
119
|
s = states.find { |st| rules.subset? st.rules } || begin
|
122
120
|
s = State.new << rules
|
123
121
|
compute_closure(s)
|
@@ -174,7 +172,6 @@ module Antelope
|
|
174
172
|
added = enum.size - added
|
175
173
|
end
|
176
174
|
end
|
177
|
-
|
178
175
|
end
|
179
176
|
end
|
180
177
|
end
|
@@ -8,7 +8,7 @@ module Antelope
|
|
8
8
|
|
9
9
|
# The grammar that the table is based off of.
|
10
10
|
#
|
11
|
-
# @return [
|
11
|
+
# @return [Grammar]
|
12
12
|
attr_accessor :grammar
|
13
13
|
|
14
14
|
# The table itself.
|
@@ -25,7 +25,7 @@ module Antelope
|
|
25
25
|
|
26
26
|
# Initialize.
|
27
27
|
#
|
28
|
-
# @param grammar [
|
28
|
+
# @param grammar [Grammar]
|
29
29
|
def initialize(grammar)
|
30
30
|
@grammar = grammar
|
31
31
|
end
|
@@ -118,15 +118,15 @@ module Antelope
|
|
118
118
|
end
|
119
119
|
|
120
120
|
def coerce_nested_hash(key, value)
|
121
|
-
parts = key.split('.').map { |p| p.gsub(/-/,
|
121
|
+
parts = key.split('.').map { |p| p.gsub(/-/, '_') }
|
122
122
|
top = {}
|
123
123
|
hash = top
|
124
|
-
parts.each_with_index do |part,
|
124
|
+
parts.each_with_index do |part, _|
|
125
125
|
hash[part] = if parts.last == part
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
126
|
+
value
|
127
|
+
else
|
128
|
+
{}
|
129
|
+
end
|
130
130
|
hash = hash[part]
|
131
131
|
end
|
132
132
|
|
@@ -162,7 +162,7 @@ module Antelope
|
|
162
162
|
# otherwise, if the first argument isn't "false", return
|
163
163
|
# true.
|
164
164
|
|
165
|
-
values[0].to_s !=
|
165
|
+
values[0].to_s != 'false'
|
166
166
|
when Array
|
167
167
|
values.zip(type).map do |value, t|
|
168
168
|
coerce_directive_value(defined, [value], t)
|