adsl 0.0.2 → 0.0.3
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 +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
|