mbt-gen 0.0.7 → 0.0.8
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/lib/mbt-gen.rb +152 -28
- data/lib/solver-lib.rb +5 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 763d26c653134a8a5432753091e286e1df8aecf8c603a5eba5bc6980ed5c3e6f
|
|
4
|
+
data.tar.gz: e5e86c5368af05ff682fbd2f7bf7fed6a9e7909d7d92523728956ee3fee71946
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5c32f100cae06aa9f7e97d7e1b214f27a9d0747948feafddd01530392f45df0a9966e4f6ad3ef5be9a719b87f9e0bd91f966523415231b539026503aa1659064
|
|
7
|
+
data.tar.gz: 485bd1dfe0f01f7e553087603c90e73c582b7dd29de72cd79032f63f1b35df32af15c66369c540507ae4ed8427244159710076221dcf033696e7ce8732191ff7
|
data/lib/mbt-gen.rb
CHANGED
|
@@ -768,9 +768,9 @@ def parse_field_value(fielddef, value)
|
|
|
768
768
|
when :int
|
|
769
769
|
return Integer(value)
|
|
770
770
|
when :string
|
|
771
|
-
return value
|
|
771
|
+
return solver_value_to_string(value)
|
|
772
772
|
when :enum
|
|
773
|
-
return value
|
|
773
|
+
return solver_value_to_string(value)
|
|
774
774
|
when :date
|
|
775
775
|
return Date.parse(value)
|
|
776
776
|
when :timestamp
|
|
@@ -778,6 +778,10 @@ def parse_field_value(fielddef, value)
|
|
|
778
778
|
end
|
|
779
779
|
end
|
|
780
780
|
|
|
781
|
+
def solver_value_to_ruby_value(fielddef, solver_value)
|
|
782
|
+
parse_field_value(fielddef, solver_value)
|
|
783
|
+
end
|
|
784
|
+
|
|
781
785
|
def solver_value_to_string(solver_value)
|
|
782
786
|
if solver_value =~ /\"(.*)\"/ then
|
|
783
787
|
return $1
|
|
@@ -786,6 +790,15 @@ def solver_value_to_string(solver_value)
|
|
|
786
790
|
end
|
|
787
791
|
end
|
|
788
792
|
|
|
793
|
+
def format_solver_value(fielddef, solver_value)
|
|
794
|
+
if fielddef[:formatter] then
|
|
795
|
+
fvalue_ruby = solver_value_to_ruby_value(fielddef, solver_value)
|
|
796
|
+
fvalue_str = fielddef[:formatter].call(fvalue_ruby)
|
|
797
|
+
else
|
|
798
|
+
fvalue_str = solver_value_to_string(solver_value)
|
|
799
|
+
end
|
|
800
|
+
end
|
|
801
|
+
|
|
789
802
|
def build_document_from_model(progress, struct, model)
|
|
790
803
|
doc = Nokogiri::XML(XML_TEMPLATE)
|
|
791
804
|
add_model_struct_to_doc(progress, struct, doc, model)
|
|
@@ -806,7 +819,8 @@ def add_model_struct_to_doc(progress, struct, doc, model, prefix = nil)
|
|
|
806
819
|
raise RuntimeError.new("xpath '#{xpath}' not contained in model.")
|
|
807
820
|
end
|
|
808
821
|
if model_value[:filled] == true || model_value[:filled] == "true" then
|
|
809
|
-
|
|
822
|
+
fvalue_str = format_solver_value(value, model_value[:value])
|
|
823
|
+
doc.add_child("<#{key}>#{fvalue_str}</#{key}>")
|
|
810
824
|
end
|
|
811
825
|
elsif value[:type] == :list then
|
|
812
826
|
node = doc.add_child("<#{key}></#{key}>")
|
|
@@ -1171,17 +1185,43 @@ def list_validation_rules(message)
|
|
|
1171
1185
|
rules.each { |r| puts " #{r}" }
|
|
1172
1186
|
end
|
|
1173
1187
|
|
|
1174
|
-
def
|
|
1175
|
-
if
|
|
1188
|
+
def default_parser_for_type(value_str, datatype)
|
|
1189
|
+
if datatype == :string or datatype == :enum then
|
|
1190
|
+
value_str
|
|
1191
|
+
elsif datatype == :int then
|
|
1192
|
+
Integer(value_str)
|
|
1193
|
+
elsif datatype == :date then
|
|
1194
|
+
Date.parse(value_str)
|
|
1195
|
+
elsif datatype == :timestamp then
|
|
1196
|
+
Time.new(value_str)
|
|
1197
|
+
else
|
|
1198
|
+
raise RuntimeError.new("encountered unknown :datatype #{datatype.inspect}")
|
|
1199
|
+
end
|
|
1200
|
+
end
|
|
1201
|
+
|
|
1202
|
+
def value_of_type_to_solver(value, datatype)
|
|
1203
|
+
if datatype == :string || datatype == :enum then
|
|
1176
1204
|
"\"#{value}\""
|
|
1177
|
-
elsif
|
|
1205
|
+
elsif datatype == :int then
|
|
1178
1206
|
value.to_s
|
|
1179
|
-
elsif
|
|
1180
|
-
(
|
|
1181
|
-
elsif
|
|
1182
|
-
(
|
|
1207
|
+
elsif datatype == :date then
|
|
1208
|
+
(value - Time.at(0).to_date).to_i.to_s
|
|
1209
|
+
elsif datatype == :timestamp then
|
|
1210
|
+
(value - Time.at(0)).to_i.to_s
|
|
1211
|
+
else
|
|
1212
|
+
raise RuntimeError.new("encountered value of unknown type: #{datatype.inspect}")
|
|
1213
|
+
end
|
|
1214
|
+
end
|
|
1215
|
+
|
|
1216
|
+
def value_of_type(value, type)
|
|
1217
|
+
value_of_type_to_solver(default_parser_for_type(value, type), type)
|
|
1218
|
+
end
|
|
1219
|
+
|
|
1220
|
+
def parse_field_value_to_ruby(fielddef, fieldvalue)
|
|
1221
|
+
if fielddef[:parser] then
|
|
1222
|
+
fielddef[:parser].call(fieldvalue)
|
|
1183
1223
|
else
|
|
1184
|
-
|
|
1224
|
+
default_parser_for_type(fieldvalue, fielddef[:datatype])
|
|
1185
1225
|
end
|
|
1186
1226
|
end
|
|
1187
1227
|
|
|
@@ -1716,6 +1756,16 @@ def validate_model(message, prefix=nil)
|
|
|
1716
1756
|
unless value[:datatype] then
|
|
1717
1757
|
raise RuntimeError.new("Model Problem: encountered field without a :datatype (key=#{key.inspect}, value=#{value.inspect})")
|
|
1718
1758
|
end
|
|
1759
|
+
if value[:parser] then
|
|
1760
|
+
unless value[:formatter] then
|
|
1761
|
+
raise RuntimeError.new("Model Problem: encountered field has a :parser, but no :formatter (key=#{key.inspect}, value=#{value.inspect})")
|
|
1762
|
+
end
|
|
1763
|
+
end
|
|
1764
|
+
if value[:formatter] then
|
|
1765
|
+
unless value[:parser] then
|
|
1766
|
+
raise RuntimeError.new("Model Problem: encountered field has a :formatter, but no :parser (key=#{key.inspect}, value=#{value.inspect})")
|
|
1767
|
+
end
|
|
1768
|
+
end
|
|
1719
1769
|
if value[:datatype] == :enum then
|
|
1720
1770
|
unless value[:values] then
|
|
1721
1771
|
raise RuntimeError.new("Model Problem: encountered enum field without a :values (key=#{key.inspect}, value=#{value.inspect})")
|
|
@@ -1803,11 +1853,11 @@ end
|
|
|
1803
1853
|
def validate_schema_against_doc_struct(struct, doc, prefix = nil)
|
|
1804
1854
|
struct.each do |key, value|
|
|
1805
1855
|
next if key == :additional_smtlib || key == :validation_rules || key == :predicates || key == :parent_link || key == :struct_xpath_prefix
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1856
|
+
if prefix then
|
|
1857
|
+
xpath = "#{prefix}/#{key}"
|
|
1858
|
+
else
|
|
1859
|
+
xpath = key
|
|
1860
|
+
end
|
|
1811
1861
|
if value[:type] == :structure then
|
|
1812
1862
|
node = doc.at_xpath(key.to_s)
|
|
1813
1863
|
if node then
|
|
@@ -1838,6 +1888,26 @@ def validate_schema_against_doc_struct(struct, doc, prefix = nil)
|
|
|
1838
1888
|
end
|
|
1839
1889
|
end
|
|
1840
1890
|
end
|
|
1891
|
+
elsif value[:type] == :objlist then
|
|
1892
|
+
if value[:optional] == false then
|
|
1893
|
+
unless doc.at_xpath(key.to_s) then
|
|
1894
|
+
raise FatalError.new("ERROR: schema validation failed: non-optional objlist #{xpath} not found in doc.")
|
|
1895
|
+
end
|
|
1896
|
+
end
|
|
1897
|
+
list = doc.at_xpath(key.to_s)
|
|
1898
|
+
if list then
|
|
1899
|
+
index = 0
|
|
1900
|
+
list.children.to_a.each_with_index do |c|
|
|
1901
|
+
next unless c.is_a?(Nokogiri::XML::Element)
|
|
1902
|
+
index += 1
|
|
1903
|
+
unless c.name == value[:xpath_element] then
|
|
1904
|
+
raise FatalError.new("ERROR: schema validation failed: encountered element #{c.name} in objlist #{xpath}, which should only contain #{value[:xpath_element]} elements.")
|
|
1905
|
+
end
|
|
1906
|
+
if c then
|
|
1907
|
+
validate_schema_against_doc_struct(value[:ref], c, "#{xpath}/#{value[:xpath_element]}[#{index}]" )
|
|
1908
|
+
end
|
|
1909
|
+
end
|
|
1910
|
+
end
|
|
1841
1911
|
else
|
|
1842
1912
|
raise RuntimeError.new("Model error: encountered element #{xpath} of unknown type: #{value[:type]}.")
|
|
1843
1913
|
end
|
|
@@ -1849,10 +1919,10 @@ def translate_doc_to_SMTLIB(progress, solver, struct, doc, hash = {})
|
|
|
1849
1919
|
config = hash[:config]
|
|
1850
1920
|
|
|
1851
1921
|
solver.to_solver(progress, "; --- Document: ---")
|
|
1852
|
-
translate_struct_in_doc_to_SMTLIB(progress, solver, struct, doc, nil, hash)
|
|
1922
|
+
translate_struct_in_doc_to_SMTLIB(progress, solver, struct, doc, nil, nil, hash)
|
|
1853
1923
|
end
|
|
1854
1924
|
|
|
1855
|
-
def translate_struct_in_doc_to_SMTLIB(progress, solver, struct, doc, prefix, hash = {})
|
|
1925
|
+
def translate_struct_in_doc_to_SMTLIB(progress, solver, struct, doc, prefix, var_prefix, hash = {})
|
|
1856
1926
|
options = hash[:options]
|
|
1857
1927
|
config = hash[:config]
|
|
1858
1928
|
|
|
@@ -1863,6 +1933,11 @@ def translate_struct_in_doc_to_SMTLIB(progress, solver, struct, doc, prefix, has
|
|
|
1863
1933
|
else
|
|
1864
1934
|
xpath = key.to_s
|
|
1865
1935
|
end
|
|
1936
|
+
if var_prefix then
|
|
1937
|
+
var_xpath = "#{var_prefix}/#{key.to_s}"
|
|
1938
|
+
else
|
|
1939
|
+
var_xpath = key.to_s
|
|
1940
|
+
end
|
|
1866
1941
|
if value[:type] == :structure then
|
|
1867
1942
|
node = doc.at_xpath(xpath)
|
|
1868
1943
|
if node then
|
|
@@ -1872,9 +1947,9 @@ def translate_struct_in_doc_to_SMTLIB(progress, solver, struct, doc, prefix, has
|
|
|
1872
1947
|
}
|
|
1873
1948
|
assertionID = "doc-#{xpath.gsub('/', '-')}"
|
|
1874
1949
|
solver.associateAssertionIDWith(assertionID, info)
|
|
1875
|
-
solver.to_solver(progress, "(assert (! (= #{exists_var_for_structure(
|
|
1950
|
+
solver.to_solver(progress, "(assert (! (= #{exists_var_for_structure(var_xpath)} true) :named #{assertionID}))")
|
|
1876
1951
|
|
|
1877
|
-
translate_struct_in_doc_to_SMTLIB(progress, solver, value[:ref], doc, xpath, hash)
|
|
1952
|
+
translate_struct_in_doc_to_SMTLIB(progress, solver, value[:ref], doc, xpath, var_xpath, hash)
|
|
1878
1953
|
else
|
|
1879
1954
|
info = {
|
|
1880
1955
|
:assertion_type => :doc_structure_not_exists,
|
|
@@ -1882,7 +1957,7 @@ def translate_struct_in_doc_to_SMTLIB(progress, solver, struct, doc, prefix, has
|
|
|
1882
1957
|
}
|
|
1883
1958
|
assertionID = "doc-#{xpath.gsub('/', '-')}"
|
|
1884
1959
|
solver.associateAssertionIDWith(assertionID, info)
|
|
1885
|
-
solver.to_solver(progress, "(assert (! (= #{exists_var_for_structure(
|
|
1960
|
+
solver.to_solver(progress, "(assert (! (= #{exists_var_for_structure(var_xpath)} false) :named #{assertionID}))")
|
|
1886
1961
|
end
|
|
1887
1962
|
elsif value[:type] == :field then
|
|
1888
1963
|
node = doc.at_xpath(xpath)
|
|
@@ -1893,10 +1968,11 @@ def translate_struct_in_doc_to_SMTLIB(progress, solver, struct, doc, prefix, has
|
|
|
1893
1968
|
:xpath => xpath,
|
|
1894
1969
|
:value => fvalue
|
|
1895
1970
|
}
|
|
1896
|
-
|
|
1897
|
-
|
|
1971
|
+
fvalue_ruby = parse_field_value_to_ruby(value, fvalue)
|
|
1972
|
+
fvalue_str = value_of_type_to_solver(fvalue_ruby, value[:datatype])
|
|
1973
|
+
assertionID = "doc-#{var_xpath.gsub('/', '-')}"
|
|
1898
1974
|
solver.associateAssertionIDWith(assertionID, info)
|
|
1899
|
-
solver.to_solver(progress, "(assert (! (and (= #{filled_var_for_field(
|
|
1975
|
+
solver.to_solver(progress, "(assert (! (and (= #{filled_var_for_field(var_xpath)} true) (= #{value_var_for_field(var_xpath)} #{fvalue_str})) :named #{assertionID}))")
|
|
1900
1976
|
else
|
|
1901
1977
|
info = {
|
|
1902
1978
|
:assertion_type => :doc_field_empty,
|
|
@@ -1904,7 +1980,7 @@ def translate_struct_in_doc_to_SMTLIB(progress, solver, struct, doc, prefix, has
|
|
|
1904
1980
|
}
|
|
1905
1981
|
assertionID = "doc-#{xpath.gsub('/', '-')}"
|
|
1906
1982
|
solver.associateAssertionIDWith(assertionID, info)
|
|
1907
|
-
solver.to_solver(progress, "(assert (! (= #{filled_var_for_field(
|
|
1983
|
+
solver.to_solver(progress, "(assert (! (= #{filled_var_for_field(var_xpath)} false) :named #{assertionID}))")
|
|
1908
1984
|
end
|
|
1909
1985
|
elsif value[:type] == :list then
|
|
1910
1986
|
node = doc.at_xpath(xpath)
|
|
@@ -1919,14 +1995,62 @@ def translate_struct_in_doc_to_SMTLIB(progress, solver, struct, doc, prefix, has
|
|
|
1919
1995
|
:xpath => xpath,
|
|
1920
1996
|
:values => fvalues
|
|
1921
1997
|
}
|
|
1922
|
-
fvalue_str = value_of_type(fvalues, value[:datatype])
|
|
1923
1998
|
assertionID = "doc-#{xpath.gsub('/', '-')}"
|
|
1924
1999
|
solver.associateAssertionIDWith(assertionID, info)
|
|
1925
2000
|
clauses = []
|
|
1926
2001
|
fvalues.each_with_index do |fvalue, index|
|
|
1927
2002
|
clauses << "(= #{value_var_for_list(xpath,index)} #{value_of_type(fvalue, value[:datatype])})"
|
|
1928
2003
|
end
|
|
1929
|
-
solver.to_solver(progress, "(assert (! (and (= #{filled_var_for_field(
|
|
2004
|
+
solver.to_solver(progress, "(assert (! (and (= #{filled_var_for_field(var_xpath)} true) (= #{size_var_for_list(xpath)} #{fvalues.size}) #{clauses.join(' ')}) :named #{assertionID}))")
|
|
2005
|
+
else
|
|
2006
|
+
info = {
|
|
2007
|
+
:assertion_type => :doc_field_empty,
|
|
2008
|
+
:xpath => xpath,
|
|
2009
|
+
}
|
|
2010
|
+
assertionID = "doc-#{xpath.gsub('/', '-')}"
|
|
2011
|
+
solver.associateAssertionIDWith(assertionID, info)
|
|
2012
|
+
solver.to_solver(progress, "(assert (! (= #{filled_var_for_field(var_xpath)} false) :named #{assertionID}))")
|
|
2013
|
+
end
|
|
2014
|
+
elsif value[:type] == :objlist then
|
|
2015
|
+
node = doc.at_xpath(xpath)
|
|
2016
|
+
if node then
|
|
2017
|
+
fvalues = []
|
|
2018
|
+
index = 0
|
|
2019
|
+
num_elements = 0
|
|
2020
|
+
value[:model_maxLength].times do |index|
|
|
2021
|
+
element_node = node.at_xpath("#{value[:xpath_element]}[#{index+1}]")
|
|
2022
|
+
element_xpath = "#{xpath}/#{value[:xpath_element]}[#{index+1}]"
|
|
2023
|
+
element_var_xpath = "#{xpath}/#{index}"
|
|
2024
|
+
if element_node then
|
|
2025
|
+
num_elements += 1
|
|
2026
|
+
info = {
|
|
2027
|
+
:assertion_type => :doc_structure_exists,
|
|
2028
|
+
:xpath => element_xpath,
|
|
2029
|
+
}
|
|
2030
|
+
assertionID = "doc-#{element_var_xpath.gsub('/', '-')}"
|
|
2031
|
+
solver.associateAssertionIDWith(assertionID, info)
|
|
2032
|
+
solver.to_solver(progress, "(assert (! (= #{exists_var_for_structure(element_var_xpath)} true) :named #{assertionID}))")
|
|
2033
|
+
|
|
2034
|
+
translate_struct_in_doc_to_SMTLIB(progress, solver, value[:ref], doc, element_xpath, element_var_xpath, hash)
|
|
2035
|
+
else
|
|
2036
|
+
info = {
|
|
2037
|
+
:assertion_type => :doc_structure_not_exists,
|
|
2038
|
+
:xpath => element_xpath,
|
|
2039
|
+
}
|
|
2040
|
+
assertionID = "doc-#{element_var_xpath.gsub('/', '-')}"
|
|
2041
|
+
solver.associateAssertionIDWith(assertionID, info)
|
|
2042
|
+
solver.to_solver(progress, "(assert (! (= #{exists_var_for_structure(element_var_xpath)} false) :named #{assertionID}))")
|
|
2043
|
+
end
|
|
2044
|
+
end
|
|
2045
|
+
info = {
|
|
2046
|
+
:assertion_type => :doc_objlist_filled,
|
|
2047
|
+
:size => num_elements,
|
|
2048
|
+
:xpath => xpath
|
|
2049
|
+
}
|
|
2050
|
+
assertionID = "doc-#{xpath.gsub('/', '-')}"
|
|
2051
|
+
solver.associateAssertionIDWith(assertionID, info)
|
|
2052
|
+
clauses = []
|
|
2053
|
+
solver.to_solver(progress, "(assert (! (and (= #{filled_var_for_field(var_xpath)} true) (= #{size_var_for_list(var_xpath)} #{num_elements})) :named #{assertionID}))")
|
|
1930
2054
|
else
|
|
1931
2055
|
info = {
|
|
1932
2056
|
:assertion_type => :doc_field_empty,
|
|
@@ -1934,7 +2058,7 @@ def translate_struct_in_doc_to_SMTLIB(progress, solver, struct, doc, prefix, has
|
|
|
1934
2058
|
}
|
|
1935
2059
|
assertionID = "doc-#{xpath.gsub('/', '-')}"
|
|
1936
2060
|
solver.associateAssertionIDWith(assertionID, info)
|
|
1937
|
-
solver.to_solver(progress, "(assert (! (= #{filled_var_for_field(
|
|
2061
|
+
solver.to_solver(progress, "(assert (! (= #{filled_var_for_field(var_xpath)} false) :named #{assertionID}))")
|
|
1938
2062
|
end
|
|
1939
2063
|
else
|
|
1940
2064
|
raise RuntimeError.new("Model Error: encountered unknown type #{value[:type].inspect}")
|
data/lib/solver-lib.rb
CHANGED
|
@@ -225,7 +225,7 @@ class SolverFactory
|
|
|
225
225
|
unsat_core = session.from_solver(@progress)
|
|
226
226
|
explanation = session.parse_unsat_core(unsat_core)
|
|
227
227
|
else
|
|
228
|
-
ModelUtils.handleSolverError(@progress, options, result)
|
|
228
|
+
ModelUtils.handleSolverError(@progress, session, options, result)
|
|
229
229
|
end
|
|
230
230
|
|
|
231
231
|
return explanation
|
|
@@ -469,6 +469,10 @@ class Z3Solver
|
|
|
469
469
|
return "Structure #{info[:xpath]} exists in document"
|
|
470
470
|
elsif info[:assertion_type] == :doc_structure_not_exists then
|
|
471
471
|
return "Structure #{info[:xpath]} does not exist in document"
|
|
472
|
+
elsif info[:assertion_type] == :doc_list_filled then
|
|
473
|
+
return "List #{info[:xpath]} is filled in document and contains the values #{info[:values].inspect}"
|
|
474
|
+
elsif info[:assertion_type] == :doc_objlist_filled then
|
|
475
|
+
return "ObjList #{info[:xpath]} is filled in document and contains #{info[:size]} elements"
|
|
472
476
|
elsif info[:assertion_type] == :constraint then
|
|
473
477
|
if info[:constraint_type] == :min then
|
|
474
478
|
return "Field #{info[:xpath]} has a minimum value of #{info[:value]}."
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mbt-gen
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- FM-enthusiast
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-08-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: nokogiri
|