rlsm 0.2.4 → 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.
- data/History.txt +0 -0
- data/Manifest.txt +3 -28
- data/README.txt +0 -0
- data/Rakefile +0 -0
- data/bin/smon +1 -3
- data/lib/data/monoids.db +0 -0
- data/lib/dfa.rb +656 -0
- data/lib/monoid.rb +778 -0
- data/lib/re.rb +492 -0
- data/lib/rlsm.rb +57 -36
- metadata +5 -30
- data/lib/rlsm/dfa.rb +0 -705
- data/lib/rlsm/exceptions.rb +0 -39
- data/lib/rlsm/mgen.rb +0 -138
- data/lib/rlsm/monkey_patching.rb +0 -126
- data/lib/rlsm/monoid.rb +0 -552
- data/lib/rlsm/monoid_db.rb +0 -123
- data/lib/rlsm/regexp.rb +0 -229
- data/lib/rlsm/regexp_nodes/concat.rb +0 -112
- data/lib/rlsm/regexp_nodes/primexp.rb +0 -49
- data/lib/rlsm/regexp_nodes/renodes.rb +0 -95
- data/lib/rlsm/regexp_nodes/star.rb +0 -50
- data/lib/rlsm/regexp_nodes/union.rb +0 -85
- data/lib/smon/commands/db_find.rb +0 -37
- data/lib/smon/commands/db_stat.rb +0 -20
- data/lib/smon/commands/exit.rb +0 -9
- data/lib/smon/commands/help.rb +0 -31
- data/lib/smon/commands/intro.rb +0 -32
- data/lib/smon/commands/monoid.rb +0 -27
- data/lib/smon/commands/quit.rb +0 -10
- data/lib/smon/commands/regexp.rb +0 -20
- data/lib/smon/commands/reload.rb +0 -22
- data/lib/smon/commands/show.rb +0 -21
- data/lib/smon/presenter.rb +0 -18
- data/lib/smon/presenter/txt_presenter.rb +0 -157
- data/lib/smon/smon.rb +0 -79
- data/test/dfa_spec.rb +0 -99
- data/test/monoid_spec.rb +0 -270
- data/test/regexp_spec.rb +0 -25
data/lib/rlsm/monoid_db.rb
DELETED
@@ -1,123 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# This file is part of the RLSM gem.
|
3
|
-
#
|
4
|
-
#(The MIT License)
|
5
|
-
#
|
6
|
-
#Copyright (c) 2008 Gunther Diemant <g.diemant@gmx.net>
|
7
|
-
#
|
8
|
-
#Permission is hereby granted, free of charge, to any person obtaining
|
9
|
-
#a copy of this software and associated documentation files (the
|
10
|
-
#'Software'), to deal in the Software without restriction, including
|
11
|
-
#without limitation the rights to use, copy, modify, merge, publish,
|
12
|
-
#distribute, sublicense, and/or sell copies of the Software, and to
|
13
|
-
#permit persons to whom the Software is furnished to do so, subject to
|
14
|
-
#the following conditions:
|
15
|
-
#
|
16
|
-
#The above copyright notice and this permission notice shall be
|
17
|
-
#included in all copies or substantial portions of the Software.
|
18
|
-
#
|
19
|
-
#THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
20
|
-
#EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
21
|
-
#MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
22
|
-
#IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
23
|
-
#CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
24
|
-
#TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
25
|
-
#SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
26
|
-
#
|
27
|
-
|
28
|
-
|
29
|
-
require "rubygems"
|
30
|
-
require "sqlite3"
|
31
|
-
require "singleton"
|
32
|
-
|
33
|
-
module RLSM
|
34
|
-
class MonoidDB
|
35
|
-
|
36
|
-
Columns = [:binop, :m_order, :num_generators,
|
37
|
-
:num_idempotents, :num_left_nulls, :num_right_nulls,
|
38
|
-
:syntactic, :idempotent, :aperiodic,
|
39
|
-
:commutative, :is_group, :has_null,
|
40
|
-
:l_trivial, :r_trivial, :d_trivial]
|
41
|
-
|
42
|
-
include Singleton
|
43
|
-
|
44
|
-
attr_reader :db
|
45
|
-
|
46
|
-
def self.query(query, &block)
|
47
|
-
if block_given?
|
48
|
-
instance.db.execute(query, &block)
|
49
|
-
else
|
50
|
-
instance.db.execute(query)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def self.find(params = {}, &block)
|
55
|
-
if block_given?
|
56
|
-
query construct_query(params), &block
|
57
|
-
else
|
58
|
-
query construct_query(params)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def self.count(params = {})
|
63
|
-
q = construct_query(params).sub('T binop F',
|
64
|
-
"T count(*), total(syntactic) F")
|
65
|
-
query(q).first.map { |x| x.to_i }
|
66
|
-
end
|
67
|
-
|
68
|
-
def self.statistic
|
69
|
-
res = instance.db.execute2 <<SQL
|
70
|
-
SELECT
|
71
|
-
m_order AS 'Order',
|
72
|
-
count(*) AS 'Total',
|
73
|
-
total(syntactic) AS 'Syntactic',
|
74
|
-
total(is_group) AS 'Groups',
|
75
|
-
total(commutative) AS 'Commutative',
|
76
|
-
total(aperiodic) AS 'Aperiodic',
|
77
|
-
total(idempotent) AS 'Idempotent'
|
78
|
-
FROM monoids
|
79
|
-
GROUP BY m_order
|
80
|
-
ORDER BY 'Order' ASC;
|
81
|
-
SQL
|
82
|
-
|
83
|
-
desc = res.shift
|
84
|
-
res.map! { |row| row.map { |x| x.to_i } }
|
85
|
-
res.unshift desc
|
86
|
-
|
87
|
-
res
|
88
|
-
end
|
89
|
-
|
90
|
-
private
|
91
|
-
def initialize
|
92
|
-
db_name = File.join(File.dirname(__FILE__), '..', 'data', 'monoids.db')
|
93
|
-
@db = SQLite3::Database.open(db_name)
|
94
|
-
end
|
95
|
-
|
96
|
-
def self.construct_query(params)
|
97
|
-
limit = ""
|
98
|
-
if params[:limit]
|
99
|
-
limit = "\nLIMIT #{params[:limit]}"
|
100
|
-
params.delete :limit
|
101
|
-
if params[:offset]
|
102
|
-
limit += " OFFSET #{params[:offset]}"
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
order_by = "\nORDER BY binop #{params[:ordering] || 'ASC'}"
|
107
|
-
|
108
|
-
params.delete :ordering
|
109
|
-
|
110
|
-
q = "SELECT binop FROM monoids"
|
111
|
-
|
112
|
-
where = Columns.map do |col|
|
113
|
-
params[col] ? ("#{col.to_s} = #{params[col]}") : nil
|
114
|
-
end.compact.join(" AND ")
|
115
|
-
|
116
|
-
if where.length > 0
|
117
|
-
q += "\nWHERE " + where
|
118
|
-
end
|
119
|
-
|
120
|
-
q + order_by + limit + ";"
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
data/lib/rlsm/regexp.rb
DELETED
@@ -1,229 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# This file is part of the RLSM gem.
|
3
|
-
#
|
4
|
-
#(The MIT License)
|
5
|
-
#
|
6
|
-
#Copyright (c) 2008 Gunther Diemant <g.diemant@gmx.net>
|
7
|
-
#
|
8
|
-
#Permission is hereby granted, free of charge, to any person obtaining
|
9
|
-
#a copy of this software and associated documentation files (the
|
10
|
-
#'Software'), to deal in the Software without restriction, including
|
11
|
-
#without limitation the rights to use, copy, modify, merge, publish,
|
12
|
-
#distribute, sublicense, and/or sell copies of the Software, and to
|
13
|
-
#permit persons to whom the Software is furnished to do so, subject to
|
14
|
-
#the following conditions:
|
15
|
-
#
|
16
|
-
#The above copyright notice and this permission notice shall be
|
17
|
-
#included in all copies or substantial portions of the Software.
|
18
|
-
#
|
19
|
-
#THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
20
|
-
#EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
21
|
-
#MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
22
|
-
#IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
23
|
-
#CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
24
|
-
#TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
25
|
-
#SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
26
|
-
#
|
27
|
-
|
28
|
-
require File.join(File.dirname(__FILE__), 'monkey_patching')
|
29
|
-
require File.join(File.dirname(__FILE__), 'exceptions.rb')
|
30
|
-
require File.join(File.dirname(__FILE__), 'regexp_nodes', 'renodes')
|
31
|
-
require File.join(File.dirname(__FILE__), 'dfa')
|
32
|
-
|
33
|
-
module RLSM
|
34
|
-
class RegExp
|
35
|
-
include RLSM::RENodes
|
36
|
-
|
37
|
-
#Creates a new RegExp from a string description. Metacharacters are
|
38
|
-
# & * | ( )
|
39
|
-
#Here & is the empty word and an empty string represents the empty set.
|
40
|
-
def initialize(desc = "")
|
41
|
-
#Is the argument a well formed RegExp?
|
42
|
-
_well_formed?(desc)
|
43
|
-
|
44
|
-
@re = RLSM::RENodes.new(desc)
|
45
|
-
end
|
46
|
-
|
47
|
-
#--
|
48
|
-
#Operations of a regexp
|
49
|
-
#++
|
50
|
-
|
51
|
-
#Kleene star of the regexp. Alters the regexp in place
|
52
|
-
def star!
|
53
|
-
#For empty set and empty word a star changes nothing.
|
54
|
-
#A double star is also useless
|
55
|
-
return if empty? or lambda? or (@re.class == Star)
|
56
|
-
str = '(' + to_s + ')*'
|
57
|
-
@re = RLSM::RENodes.new(str)
|
58
|
-
|
59
|
-
#Unset the str rep
|
60
|
-
@re_str = nil
|
61
|
-
|
62
|
-
self
|
63
|
-
end
|
64
|
-
|
65
|
-
#Returns the kleene star of this regexp. Leaves the regexp untouched.
|
66
|
-
def star
|
67
|
-
self.deep_copy.star!
|
68
|
-
end
|
69
|
-
|
70
|
-
#Returns the concatenation of two regexps
|
71
|
-
def *(other)
|
72
|
-
return RegExp.new if empty? or other.empty?
|
73
|
-
RegExp.new('(' + to_s + ')(' + other.to_s + ')')
|
74
|
-
end
|
75
|
-
|
76
|
-
#Returns the union of two regexps
|
77
|
-
def +(other)
|
78
|
-
return self.deep_copy if other.empty?
|
79
|
-
return other.deep_copy if empty?
|
80
|
-
RegExp.new('(' + to_s + ')|(' + other.to_s + ')')
|
81
|
-
end
|
82
|
-
|
83
|
-
#--
|
84
|
-
#Some small flags
|
85
|
-
#++
|
86
|
-
#Returns true if this regexp is the empty word.
|
87
|
-
def lambda?
|
88
|
-
@re.lambda?
|
89
|
-
end
|
90
|
-
|
91
|
-
#Returns true if this regexp is the empty set.
|
92
|
-
def empty?
|
93
|
-
@re.empty?
|
94
|
-
end
|
95
|
-
|
96
|
-
#Returns true if the empty word matches this regexp
|
97
|
-
def null?
|
98
|
-
@re.null?
|
99
|
-
end
|
100
|
-
|
101
|
-
#--
|
102
|
-
#Some properties of a regexp
|
103
|
-
#++
|
104
|
-
|
105
|
-
#Returns an array of beginning symbols of the regexp.
|
106
|
-
def first
|
107
|
-
@re.first
|
108
|
-
end
|
109
|
-
|
110
|
-
#Returns an array of end symbols of the regexp.
|
111
|
-
def last
|
112
|
-
@re.last
|
113
|
-
end
|
114
|
-
|
115
|
-
#Returns an array of all possible two letter substrings of words matched by the regexp.
|
116
|
-
def follow
|
117
|
-
@re.follow.uniq
|
118
|
-
end
|
119
|
-
|
120
|
-
#--
|
121
|
-
#Conversion methods
|
122
|
-
#++
|
123
|
-
#Returns a string representation of the regexp
|
124
|
-
def to_s
|
125
|
-
@re_str ||= @re.to_s
|
126
|
-
end
|
127
|
-
|
128
|
-
#Returns a minimal DFA which accepts the same language as the regexp.
|
129
|
-
def to_dfa
|
130
|
-
#Step 1: Substitute every char such that every character is unique
|
131
|
-
#Add also a beginning marker
|
132
|
-
|
133
|
-
orig = []
|
134
|
-
rre = [0]
|
135
|
-
to_s.each_char do |c|
|
136
|
-
if ['(', ')', '|', '*', '&'].include? c
|
137
|
-
rre << c
|
138
|
-
else
|
139
|
-
orig << c
|
140
|
-
rre << (orig.size)
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
tmp_re = RLSM::RENodes.new(rre)
|
145
|
-
|
146
|
-
#Step 2a: Construct a DFA representation of this new regexp
|
147
|
-
#Step 2b: reverse the substitution (yields (maybe) a NFA)
|
148
|
-
|
149
|
-
alph = orig.uniq
|
150
|
-
initial = 0
|
151
|
-
|
152
|
-
tmp_finals = tmp_re.last
|
153
|
-
|
154
|
-
tmp_trans = tmp_re.follow.map do |s1,s2|
|
155
|
-
[orig[s2-1], s1, s2]
|
156
|
-
end
|
157
|
-
|
158
|
-
#Step 4: Transform the NFA to a DFA
|
159
|
-
states = [[0]]
|
160
|
-
new_states = [[0]]
|
161
|
-
trans = []
|
162
|
-
while new_states.size > 0
|
163
|
-
tmp = new_states.deep_copy
|
164
|
-
new_states = []
|
165
|
-
|
166
|
-
tmp.each do |new_state|
|
167
|
-
alph.each do |char|
|
168
|
-
tr_set = tmp_trans.find_all do |c,s1,s2|
|
169
|
-
c == char and new_state.include? s1
|
170
|
-
end
|
171
|
-
|
172
|
-
unless tr_set.empty?
|
173
|
-
state = tr_set.map { |c,s1,s2| s2 }.sort
|
174
|
-
|
175
|
-
#Found a new state?
|
176
|
-
unless states.include? state
|
177
|
-
new_states << state
|
178
|
-
states << state
|
179
|
-
end
|
180
|
-
|
181
|
-
tr = [char, states.index(new_state), states.index(state)]
|
182
|
-
|
183
|
-
#Found new trans?
|
184
|
-
trans << tr unless trans.include? tr
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
finals = states.find_all do |state|
|
191
|
-
tmp_finals.any? { |tf| state.include? tf }
|
192
|
-
end.map { |fi| states.index(fi) }
|
193
|
-
|
194
|
-
states = (0...states.size).to_a
|
195
|
-
|
196
|
-
#Step 5: Return the result
|
197
|
-
RLSM::DFA.new(alph,states,initial,finals,trans).minimize(:rename_states => true)
|
198
|
-
end
|
199
|
-
|
200
|
-
def inspect # :nodoc:
|
201
|
-
"<#{self.class} : '#{to_s}' >"
|
202
|
-
end
|
203
|
-
|
204
|
-
#Returns true if the two regexps are the same, i.e. the dfas are isomorphic.
|
205
|
-
def ==(other)
|
206
|
-
to_dfa == other.to_dfa
|
207
|
-
end
|
208
|
-
|
209
|
-
|
210
|
-
private
|
211
|
-
def _well_formed?(str)
|
212
|
-
#parantheses must be balanced, somthing like |) or *a or (| isn't allowed
|
213
|
-
#1 balanced parenthesis
|
214
|
-
state = 0
|
215
|
-
str.each_char do |c|
|
216
|
-
state += RLSM::RENodes::PCount[c]
|
217
|
-
end
|
218
|
-
|
219
|
-
if state != 0
|
220
|
-
raise RegExpException, "Unbalanced parenthesis in #{str}"
|
221
|
-
end
|
222
|
-
|
223
|
-
#2 bad sequenzes
|
224
|
-
if str =~ /\(\)|\|\)|\(\||\|\*|^\*|\(\*/
|
225
|
-
raise RegExpException, "Bad character sequence #{$&} found in #{str}"
|
226
|
-
end
|
227
|
-
end
|
228
|
-
end
|
229
|
-
end
|
@@ -1,112 +0,0 @@
|
|
1
|
-
module RLSM::RENodes
|
2
|
-
private
|
3
|
-
class Concat
|
4
|
-
def initialize(parent, str)
|
5
|
-
@parent = parent
|
6
|
-
@childs = _split(str).map do |substr|
|
7
|
-
RLSM::RENodes.new(substr, self)
|
8
|
-
end.reject { |child| child.lambda? }
|
9
|
-
end
|
10
|
-
|
11
|
-
def null?
|
12
|
-
@childs.all? { |child| child.null? }
|
13
|
-
end
|
14
|
-
|
15
|
-
def first
|
16
|
-
res = []
|
17
|
-
@childs.each do |child|
|
18
|
-
child.first.each do |f|
|
19
|
-
res << f
|
20
|
-
end
|
21
|
-
|
22
|
-
break unless child.null?
|
23
|
-
end
|
24
|
-
|
25
|
-
res
|
26
|
-
end
|
27
|
-
|
28
|
-
def last
|
29
|
-
res = []
|
30
|
-
@childs.reverse.each do |child|
|
31
|
-
child.last.each do |f|
|
32
|
-
res << f
|
33
|
-
end
|
34
|
-
|
35
|
-
break unless child.null?
|
36
|
-
end
|
37
|
-
|
38
|
-
res
|
39
|
-
end
|
40
|
-
|
41
|
-
def follow
|
42
|
-
res = []
|
43
|
-
|
44
|
-
@childs.each do |child|
|
45
|
-
child.follow.each do |f|
|
46
|
-
res << f
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
(1...@childs.size).each do |i|
|
51
|
-
@childs[i-1].last.each do |l|
|
52
|
-
@childs[(i..-1)].each do |ch|
|
53
|
-
ch.first.each do |f|
|
54
|
-
res << [l,f]
|
55
|
-
end
|
56
|
-
|
57
|
-
break unless ch.null?
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
res
|
63
|
-
end
|
64
|
-
|
65
|
-
def to_s
|
66
|
-
@childs.map { |child| child.to_s }.join
|
67
|
-
end
|
68
|
-
|
69
|
-
def lambda?
|
70
|
-
false
|
71
|
-
end
|
72
|
-
|
73
|
-
def empty?
|
74
|
-
false
|
75
|
-
end
|
76
|
-
|
77
|
-
private
|
78
|
-
def _split(str)
|
79
|
-
state = 0
|
80
|
-
count = Hash.new(0)
|
81
|
-
count['('] = 1
|
82
|
-
count[')'] = -1
|
83
|
-
|
84
|
-
res = [[]]
|
85
|
-
previous = nil
|
86
|
-
str.each_char do |c|
|
87
|
-
state += count[c]
|
88
|
-
|
89
|
-
if state == 1 and c == '('
|
90
|
-
res << []
|
91
|
-
res.last << c
|
92
|
-
elsif state == 0 and c == '*'
|
93
|
-
if previous == ')'
|
94
|
-
res[-2] << c
|
95
|
-
else
|
96
|
-
res << [res.last.pop, c]
|
97
|
-
res << []
|
98
|
-
end
|
99
|
-
elsif state == 0 and c == ')'
|
100
|
-
res.last << c
|
101
|
-
res << []
|
102
|
-
else
|
103
|
-
res.last << c
|
104
|
-
end
|
105
|
-
|
106
|
-
previous = c
|
107
|
-
end
|
108
|
-
|
109
|
-
res.select { |subarr| subarr.size > 0 }#.map { |substr| substr.join }
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|