adsl 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +4 -1
- data/README.md +33 -6
- data/lib/ds/data_store_spec.rb +2 -2
- data/lib/fol/first_order_logic.rb +3 -4
- data/lib/parser/adsl_ast.rb +10 -11
- data/lib/parser/adsl_parser.racc +2 -2
- data/lib/parser/adsl_parser.rex +1 -1
- data/lib/parser/adsl_parser.rex.rb +121 -118
- data/lib/parser/adsl_parser.tab.rb +163 -163
- data/lib/spass/spass_translator.rb +16 -6
- data/lib/util/csv_hash_formatter.rb +10 -2
- data/lib/util/util.rb +11 -7
- metadata +107 -128
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6b26fde19cd7f72d505d12b67a37e9eb7c76aba2
|
4
|
+
data.tar.gz: 425182f63a8d718786e63dc9f21439c764f9332a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a15fbddc4618acafd6cfe069195656f11ac0ec58ac3d22b36341fa90b0c5a690d15e3ad5c687a0a1c3af134e82093428a93a07737d19f09fcd7241dca437c1a6
|
7
|
+
data.tar.gz: 6f84daa5917019dbf27dc523e693d7eee093329de27826777b85c9ce173a09268751e396cbba04d55984e3bdc48c7363b66c12492b3a74428da06ea75facc5f9
|
data/Gemfile
CHANGED
@@ -7,7 +7,7 @@ source "http://rubygems.org"
|
|
7
7
|
gem "i18n"
|
8
8
|
|
9
9
|
# lexer/parser
|
10
|
-
gem "
|
10
|
+
gem "rexical"
|
11
11
|
gem "racc"
|
12
12
|
|
13
13
|
# used all over the place
|
@@ -15,3 +15,6 @@ gem "active_support"
|
|
15
15
|
|
16
16
|
# terminal color output
|
17
17
|
gem "colorize"
|
18
|
+
|
19
|
+
# extraction tools
|
20
|
+
gem "ruby_parser"
|
data/README.md
CHANGED
@@ -1,11 +1,32 @@
|
|
1
1
|
ADSL - Abstract Data Store Language Parser and Translator
|
2
2
|
=========================================================
|
3
3
|
|
4
|
-
This
|
4
|
+
This tool an Abstract Data Store Language (ADSL) specification verification tool.
|
5
|
+
|
6
|
+
ADSL is a language for specifying Abstract Data Stores using a syntax familiar to anyone that has experience
|
7
|
+
with ORM tools such as Hibernate and ActiveRecord. A specification contains the model classes, actions executed
|
8
|
+
using a RESTful interface, and a set of invariants to be verified.
|
9
|
+
|
10
|
+
This tool verifies a specification by translating it into a first order logic theorem verifiable by [Spass] [1],
|
11
|
+
a theorem prover. It provides detailed information on the actions and invariants verified in human-readable or
|
12
|
+
CSV format.
|
13
|
+
|
14
|
+
This tool is distributed as a Ruby gem and is uploaded to [RubyGems.org] [2]. Install it and give it a try!
|
15
|
+
|
5
16
|
|
6
17
|
Installation
|
7
18
|
------------
|
8
19
|
|
20
|
+
This gem is tested on 32 and 64 bit Linux. OS-X compatibility not tested, give it a try
|
21
|
+
and tell us if it works! Windows is not supported at this moment.
|
22
|
+
|
23
|
+
- Ruby 1.8.7 or later required. We suggest using the [Ruby Version Manager](https://rvm.io/rvm/install/) to manage this installation.
|
24
|
+
- [Download and install Spass](http://www.spass-prover.org/download/index.html) and make sure its executable (`bin/SPASS`) on your $PATH
|
25
|
+
- Install the ADSL gem by running `gem install adsl`.
|
26
|
+
|
27
|
+
If you receive an error while generating documentation for 'activesupport' run `gem install rdoc adsl` instead.
|
28
|
+
- Test the installation by verifying [the example specification](https://raw.github.com/Bocete/adsl/master/example/running-example.adsl)
|
29
|
+
|
9
30
|
Usage
|
10
31
|
-----
|
11
32
|
|
@@ -14,28 +35,31 @@ Usage
|
|
14
35
|
For options and other modes of operation, run
|
15
36
|
|
16
37
|
adsl-verify --help
|
17
|
-
|
38
|
+
|
39
|
+
You can download sample ADSL specifications
|
40
|
+
|
41
|
+
|
18
42
|
Development
|
19
43
|
-----------
|
20
44
|
|
21
45
|
### Source Repository
|
22
46
|
|
23
|
-
The ADSL gem is currently hosted at github. The github web page is
|
24
|
-
|
47
|
+
The ADSL gem is currently hosted at github. The github web page is http://github.com/Bocete/adsl.
|
48
|
+
You can download the source using our public git clone URL:
|
25
49
|
|
26
50
|
git://github.com/Bocete/adsl.git
|
27
51
|
|
28
52
|
### Issues and Bug Reports
|
29
53
|
|
30
|
-
Feature requests and bug reports can be made
|
54
|
+
Feature requests and bug reports can be made at https://github.com/Bocete/adsl/issues
|
31
55
|
|
32
|
-
https://github.com/Bocete/adsl/issues
|
33
56
|
|
34
57
|
License
|
35
58
|
-------
|
36
59
|
|
37
60
|
Rake is available under a [Lesser GPL (LGPL) license](LICENSE).
|
38
61
|
|
62
|
+
|
39
63
|
Warranty
|
40
64
|
--------
|
41
65
|
|
@@ -43,3 +67,6 @@ This software is provided "as is" and without any express or
|
|
43
67
|
implied warranties, including, without limitation, the implied
|
44
68
|
warranties of merchantibility and fitness for a particular
|
45
69
|
purpose.
|
70
|
+
|
71
|
+
[1]: http://www.spass-prover.org/ "Spass"
|
72
|
+
[2]: https://rubygems.org/gems/adsl "RubyGems.org"
|
data/lib/ds/data_store_spec.rb
CHANGED
@@ -12,7 +12,7 @@ module DS
|
|
12
12
|
|
13
13
|
def replace(what, with)
|
14
14
|
to_inspect = [self]
|
15
|
-
inspected = Set
|
15
|
+
inspected = Set.new
|
16
16
|
replaced = false
|
17
17
|
while not to_inspect.empty?
|
18
18
|
elem = to_inspect.pop
|
@@ -26,7 +26,7 @@ module DS
|
|
26
26
|
end
|
27
27
|
inspected << elem[i]
|
28
28
|
end
|
29
|
-
elsif elem.class.methods.include? 'container_for_fields'
|
29
|
+
elsif elem.class.methods.include? 'container_for_fields' or elem.class.methods.include? :container_for_fields
|
30
30
|
elem.class.container_for_fields.each do |field_name|
|
31
31
|
field_val = elem.send field_name
|
32
32
|
if field_val == what
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'rubygems'
|
2
1
|
require 'active_support/all'
|
3
2
|
require 'util/util'
|
4
3
|
|
@@ -247,12 +246,12 @@ module FOL
|
|
247
246
|
end
|
248
247
|
end
|
249
248
|
|
250
|
-
# define a
|
249
|
+
# define a method for each of the above classes, starting with underscore and underscored* afterwards
|
251
250
|
# *see: http://api.rubyonrails.org/v2.3.8/classes/ActiveSupport/CoreExtensions/String/Inflections.html
|
252
251
|
self.constants.each do |klass_name|
|
253
252
|
instance_eval do
|
254
|
-
klass = FOL.const_get
|
255
|
-
|
253
|
+
klass = FOL.const_get klass_name
|
254
|
+
send :define_method, "_#{klass_name.to_s.underscore}".to_sym do |*args|
|
256
255
|
klass.new(*args).resolve_spass
|
257
256
|
end
|
258
257
|
end
|
data/lib/parser/adsl_ast.rb
CHANGED
@@ -214,7 +214,7 @@ module ADSL
|
|
214
214
|
# name => [astnode, dsobj]
|
215
215
|
@classes = ActiveSupport::OrderedHash.new
|
216
216
|
# classname => name => [astnode, dsobj]
|
217
|
-
@relations = ActiveSupport::OrderedHash.new
|
217
|
+
@relations = ActiveSupport::OrderedHash.new{ |hash, key| hash[key] = ActiveSupport::OrderedHash.new }
|
218
218
|
# stack of name => [astnode, dsobj]
|
219
219
|
@actions = ActiveSupport::OrderedHash.new
|
220
220
|
@invariants = []
|
@@ -234,10 +234,7 @@ module ADSL
|
|
234
234
|
end
|
235
235
|
@actions = source.actions.dup
|
236
236
|
@invariants = source.invariants.dup
|
237
|
-
@var_stack =
|
238
|
-
source.var_stack.each do |frame|
|
239
|
-
@var_stack << frame.dup
|
240
|
-
end
|
237
|
+
@var_stack = source.var_stack.map{ |frame| frame.dup }
|
241
238
|
end
|
242
239
|
|
243
240
|
def on_var_write(&block)
|
@@ -312,10 +309,10 @@ module ADSL
|
|
312
309
|
def self.context_vars_that_differ(*contexts)
|
313
310
|
vars_per_context = []
|
314
311
|
contexts.each do |context|
|
315
|
-
vars_per_context << context.var_stack.inject(
|
312
|
+
vars_per_context << context.var_stack.inject(ActiveSupport::OrderedHash.new) { |so_far, frame| so_far.merge! frame }
|
316
313
|
end
|
317
314
|
all_vars = vars_per_context.map{ |c| c.keys }.flatten.uniq
|
318
|
-
packed =
|
315
|
+
packed = ActiveSupport::OrderedHash.new
|
319
316
|
all_vars.each do |v|
|
320
317
|
packed[v] = vars_per_context.map{ |vpc| vpc[v][1] }
|
321
318
|
end
|
@@ -466,23 +463,25 @@ module ADSL
|
|
466
463
|
|
467
464
|
def typecheck_and_resolve(context)
|
468
465
|
context.push_frame
|
466
|
+
|
469
467
|
contexts = [context]
|
470
|
-
(
|
468
|
+
(@blocks.length-1).times do
|
471
469
|
contexts << context.dup
|
472
470
|
end
|
473
|
-
|
471
|
+
|
474
472
|
blocks = []
|
475
473
|
@blocks.length.times do |i|
|
476
474
|
blocks << @blocks[i].typecheck_and_resolve(contexts[i])
|
477
475
|
end
|
478
476
|
|
479
|
-
contexts.each do |
|
480
|
-
|
477
|
+
contexts.each do |c|
|
478
|
+
c.pop_frame
|
481
479
|
end
|
482
480
|
|
483
481
|
either = DS::DSEither.new :blocks => blocks
|
484
482
|
|
485
483
|
lambdas = []
|
484
|
+
|
486
485
|
ADSLTypecheckResolveContext::context_vars_that_differ(*contexts).each do |var_name, vars|
|
487
486
|
var = DS::DSVariable.new :name => var_name, :type => vars.first.type
|
488
487
|
objset = DS::DSEitherLambdaObjset.new :either => either, :vars => vars
|
data/lib/parser/adsl_parser.racc
CHANGED
data/lib/parser/adsl_parser.rex
CHANGED
@@ -42,7 +42,7 @@ rule
|
|
42
42
|
= { [text, lineno] }
|
43
43
|
\+ { [text, lineno] }
|
44
44
|
[01] { [text, lineno] }
|
45
|
-
\w+ { [:IDENT, ADSLIdent.new(:lineno => lineno, :text => text)] }
|
45
|
+
\w+ { [:IDENT, ADSL::ADSLIdent.new(:lineno => lineno, :text => text)] }
|
46
46
|
\s # blank, no action
|
47
47
|
. { [:unknown_symbol, [text, lineno]] }
|
48
48
|
end
|
@@ -1,196 +1,199 @@
|
|
1
1
|
#--
|
2
2
|
# DO NOT MODIFY!!!!
|
3
|
-
# This file is automatically generated by rex 1.0.
|
3
|
+
# This file is automatically generated by rex 1.0.5
|
4
4
|
# from lexical definition file "./lib/parser/adsl_parser.rex".
|
5
5
|
#++
|
6
6
|
|
7
7
|
require 'racc/parser'
|
8
8
|
require 'parser/adsl_ast'
|
9
9
|
|
10
|
-
|
11
|
-
class ADSLParser < Racc::Parser
|
10
|
+
class ADSL::ADSLParser < Racc::Parser
|
12
11
|
require 'strscan'
|
13
12
|
|
14
13
|
class ScanError < StandardError ; end
|
15
14
|
|
16
|
-
attr_reader
|
17
|
-
attr_reader
|
15
|
+
attr_reader :lineno
|
16
|
+
attr_reader :filename
|
17
|
+
attr_accessor :state
|
18
18
|
|
19
|
-
def scan_setup
|
19
|
+
def scan_setup(str)
|
20
|
+
@ss = StringScanner.new(str)
|
21
|
+
@lineno = 1
|
22
|
+
@state = nil
|
23
|
+
end
|
20
24
|
|
21
|
-
def action
|
25
|
+
def action
|
22
26
|
yield
|
23
27
|
end
|
24
28
|
|
25
|
-
def scan_str(
|
26
|
-
|
29
|
+
def scan_str(str)
|
30
|
+
scan_setup(str)
|
27
31
|
do_parse
|
28
32
|
end
|
33
|
+
alias :scan :scan_str
|
29
34
|
|
30
35
|
def load_file( filename )
|
31
36
|
@filename = filename
|
32
37
|
open(filename, "r") do |f|
|
33
|
-
|
38
|
+
scan_setup(f.read)
|
34
39
|
end
|
35
40
|
end
|
36
41
|
|
37
42
|
def scan_file( filename )
|
38
|
-
load_file
|
43
|
+
load_file(filename)
|
39
44
|
do_parse
|
40
45
|
end
|
41
46
|
|
47
|
+
|
42
48
|
def next_token
|
43
|
-
@
|
49
|
+
return if @ss.eos?
|
50
|
+
|
51
|
+
# skips empty actions
|
52
|
+
until token = _next_token or @ss.eos?; end
|
53
|
+
token
|
44
54
|
end
|
45
55
|
|
46
|
-
def
|
47
|
-
|
48
|
-
@
|
49
|
-
@
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
@lineno += 1 if text == "\n"
|
55
|
-
case state
|
56
|
-
when nil
|
57
|
-
case
|
58
|
-
when (text = ss.scan(/\/\/[^\n\z]*/))
|
59
|
-
;
|
56
|
+
def _next_token
|
57
|
+
text = @ss.peek(1)
|
58
|
+
@lineno += 1 if text == "\n"
|
59
|
+
token = case @state
|
60
|
+
when nil
|
61
|
+
case
|
62
|
+
when (text = @ss.scan(/\/\/[^\n\z]*/))
|
63
|
+
;
|
60
64
|
|
61
|
-
|
62
|
-
|
65
|
+
when (text = @ss.scan(/\#[^\n\z]*/))
|
66
|
+
;
|
63
67
|
|
64
|
-
|
65
|
-
|
68
|
+
when (text = @ss.scan(/\/\*(?:[^\*]*(?:\*+[^\/]+)?)*\*\//))
|
69
|
+
;
|
66
70
|
|
67
|
-
|
68
|
-
|
71
|
+
when (text = @ss.scan(/class\b/))
|
72
|
+
action { [:class, lineno] }
|
69
73
|
|
70
|
-
|
71
|
-
|
74
|
+
when (text = @ss.scan(/extends\b/))
|
75
|
+
action { [:extends, lineno] }
|
72
76
|
|
73
|
-
|
74
|
-
|
77
|
+
when (text = @ss.scan(/inverseof\b/))
|
78
|
+
action { [:inverseof, lineno] }
|
75
79
|
|
76
|
-
|
77
|
-
|
80
|
+
when (text = @ss.scan(/create\b/))
|
81
|
+
action { [:create, lineno] }
|
78
82
|
|
79
|
-
|
80
|
-
|
83
|
+
when (text = @ss.scan(/delete\b/))
|
84
|
+
action { [:delete, lineno] }
|
81
85
|
|
82
|
-
|
83
|
-
|
86
|
+
when (text = @ss.scan(/foreach\b/))
|
87
|
+
action { [:foreach, lineno] }
|
84
88
|
|
85
|
-
|
86
|
-
|
89
|
+
when (text = @ss.scan(/either\b/))
|
90
|
+
action { [:either, lineno] }
|
87
91
|
|
88
|
-
|
89
|
-
|
92
|
+
when (text = @ss.scan(/action\b/))
|
93
|
+
action { [:action, lineno] }
|
90
94
|
|
91
|
-
|
92
|
-
|
95
|
+
when (text = @ss.scan(/or\b/))
|
96
|
+
action { [:or, lineno] }
|
93
97
|
|
94
|
-
|
95
|
-
|
98
|
+
when (text = @ss.scan(/subset\b/))
|
99
|
+
action { [:subset, lineno] }
|
96
100
|
|
97
|
-
|
98
|
-
|
101
|
+
when (text = @ss.scan(/oneof\b/))
|
102
|
+
action { [:oneof, lineno] }
|
99
103
|
|
100
|
-
|
101
|
-
|
104
|
+
when (text = @ss.scan(/\.\s*all\b/))
|
105
|
+
action { [:dotall, lineno] }
|
102
106
|
|
103
|
-
|
104
|
-
|
107
|
+
when (text = @ss.scan(/forall\b/))
|
108
|
+
action { [:forall, lineno] }
|
105
109
|
|
106
|
-
|
107
|
-
|
110
|
+
when (text = @ss.scan(/exists\b/))
|
111
|
+
action { [:exists, lineno] }
|
108
112
|
|
109
|
-
|
110
|
-
|
113
|
+
when (text = @ss.scan(/in\b/))
|
114
|
+
action { [:in, lineno] }
|
111
115
|
|
112
|
-
|
113
|
-
|
116
|
+
when (text = @ss.scan(/invariant\b/))
|
117
|
+
action { [:invariant, lineno] }
|
114
118
|
|
115
|
-
|
116
|
-
|
119
|
+
when (text = @ss.scan(/true\b/))
|
120
|
+
action { [:true, lineno] }
|
117
121
|
|
118
|
-
|
119
|
-
|
122
|
+
when (text = @ss.scan(/false\b/))
|
123
|
+
action { [:false, lineno] }
|
120
124
|
|
121
|
-
|
122
|
-
|
125
|
+
when (text = @ss.scan(/!=/))
|
126
|
+
action { [text, lineno] }
|
123
127
|
|
124
|
-
|
125
|
-
|
128
|
+
when (text = @ss.scan(/!|not\b/))
|
129
|
+
action { [:not, lineno] }
|
126
130
|
|
127
|
-
|
128
|
-
|
131
|
+
when (text = @ss.scan(/and\b/))
|
132
|
+
action { [:and, lineno] }
|
129
133
|
|
130
|
-
|
131
|
-
|
134
|
+
when (text = @ss.scan(/equal\b/))
|
135
|
+
action { [:equal, lineno] }
|
132
136
|
|
133
|
-
|
134
|
-
|
137
|
+
when (text = @ss.scan(/equiv\b/))
|
138
|
+
action { [:equiv, lineno] }
|
135
139
|
|
136
|
-
|
137
|
-
|
140
|
+
when (text = @ss.scan(/empty\b/))
|
141
|
+
action { [:empty, lineno] }
|
138
142
|
|
139
|
-
|
140
|
-
|
143
|
+
when (text = @ss.scan(/implies\b/))
|
144
|
+
action { [:implies, lineno] }
|
141
145
|
|
142
|
-
|
143
|
-
|
146
|
+
when (text = @ss.scan(/\.\./))
|
147
|
+
action { [text, lineno] }
|
144
148
|
|
145
|
-
|
146
|
-
|
149
|
+
when (text = @ss.scan(/[{}:\(\)\.,]/))
|
150
|
+
action { [text, lineno] }
|
147
151
|
|
148
|
-
|
149
|
-
|
152
|
+
when (text = @ss.scan(/\+=/))
|
153
|
+
action { [text, lineno] }
|
150
154
|
|
151
|
-
|
152
|
-
|
155
|
+
when (text = @ss.scan(/\-=/))
|
156
|
+
action { [text, lineno] }
|
153
157
|
|
154
|
-
|
155
|
-
|
158
|
+
when (text = @ss.scan(/==/))
|
159
|
+
action { [text, lineno] }
|
156
160
|
|
157
|
-
|
158
|
-
|
161
|
+
when (text = @ss.scan(/<=>/))
|
162
|
+
action { [text, lineno] }
|
159
163
|
|
160
|
-
|
161
|
-
|
164
|
+
when (text = @ss.scan(/<=/))
|
165
|
+
action { [text, lineno] }
|
162
166
|
|
163
|
-
|
164
|
-
|
167
|
+
when (text = @ss.scan(/=>/))
|
168
|
+
action { [text, lineno] }
|
165
169
|
|
166
|
-
|
167
|
-
|
170
|
+
when (text = @ss.scan(/=/))
|
171
|
+
action { [text, lineno] }
|
168
172
|
|
169
|
-
|
170
|
-
|
173
|
+
when (text = @ss.scan(/\+/))
|
174
|
+
action { [text, lineno] }
|
171
175
|
|
172
|
-
|
173
|
-
|
176
|
+
when (text = @ss.scan(/[01]/))
|
177
|
+
action { [text, lineno] }
|
174
178
|
|
175
|
-
|
176
|
-
|
179
|
+
when (text = @ss.scan(/\w+/))
|
180
|
+
action { [:IDENT, ADSL::ADSLIdent.new(:lineno => lineno, :text => text)] }
|
177
181
|
|
178
|
-
|
179
|
-
|
182
|
+
when (text = @ss.scan(/\s/))
|
183
|
+
;
|
180
184
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
else
|
185
|
-
text = ss.string[ss.pos .. -1]
|
186
|
-
raise ScanError, "can not match: '" + text + "'"
|
187
|
-
end # if
|
185
|
+
when (text = @ss.scan(/./))
|
186
|
+
action { [:unknown_symbol, [text, lineno]] }
|
188
187
|
|
189
188
|
else
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
189
|
+
text = @ss.string[@ss.pos .. -1]
|
190
|
+
raise ScanError, "can not match: '" + text + "'"
|
191
|
+
end # if
|
192
|
+
|
193
|
+
else
|
194
|
+
raise ScanError, "undefined state: '" + state.to_s + "'"
|
195
|
+
end # case state
|
196
|
+
token
|
197
|
+
end # def _next_token
|
194
198
|
|
195
199
|
end # class
|
196
|
-
end # module
|