├── .gitattributes
├── .gitignore
├── .larabot.conf
├── .sbtopts
├── CHANGELOG.md
├── IDEAS.md
├── LICENSE
├── README.md
├── ROADMAP.md
├── TODO.md
├── build.sbt
├── project
├── build.properties
└── plugins.sbt
└── src
├── it
├── resources
│ └── regression
│ │ └── smtlib
│ │ ├── parsing
│ │ ├── eq_diamond100.smt2
│ │ └── eq_diamond50.smt2
│ │ └── solving
│ │ ├── all
│ │ ├── NEQ046_size3.smt2
│ │ ├── PEQ011_size5.smt2
│ │ ├── PEQ012_size3.smt2
│ │ ├── SEQ004_size5.smt2
│ │ ├── a20test0001.smt2
│ │ ├── array_free.smt2
│ │ ├── b159test0001.smt2
│ │ ├── bf7.smt2
│ │ ├── broken.smt2
│ │ ├── cl5_nebula_array_0001.fof.smt2
│ │ ├── define_fun1.smt2
│ │ ├── eq_diamond1.smt2
│ │ ├── eq_diamond2.smt2
│ │ ├── eq_diamond3.smt2
│ │ └── quaternion_ds1_symm_0818.fof.smt2
│ │ ├── cvc4
│ │ ├── define_fun2.smt2
│ │ ├── define_fun2.smt2.want
│ │ ├── define_fun3.smt2
│ │ └── define_fun3.smt2.want
│ │ └── z3
│ │ ├── NEQ004_size5.smt2
│ │ ├── NEQ006_size4.smt2
│ │ ├── NEQ016_size7.smt2
│ │ ├── PEQ002_size5.smt2
│ │ ├── PEQ010_size7.smt2
│ │ └── cmu-model15.smt2
└── scala
│ └── smtlib
│ └── it
│ ├── ProcessInterpreterTests.scala
│ ├── SmtLibRunnerTests.scala
│ ├── TestHelpers.scala
│ └── TheoriesBuilderTests.scala
├── main
└── scala
│ └── smtlib
│ ├── Interpreter.scala
│ ├── common
│ ├── Binary.scala
│ ├── Hexadecimal.scala
│ ├── LinkedList.scala
│ └── Positions.scala
│ ├── drivers
│ ├── Main.scala
│ ├── SemanticsDriver.scala
│ ├── cvc4
│ │ └── SemanticsDecorator.scala
│ └── package.scala
│ ├── extensions
│ └── tip
│ │ ├── Parser.scala
│ │ └── Trees.scala
│ ├── interpreters
│ ├── CVC4Interpreter.scala
│ ├── ProcessInterpreter.scala
│ └── Z3Interpreter.scala
│ ├── lexer
│ ├── Lexer.scala
│ └── Tokens.scala
│ ├── parser
│ ├── Parser.scala
│ ├── ParserCommands.scala
│ ├── ParserCommandsResponses.scala
│ ├── ParserCommon.scala
│ └── ParserTerms.scala
│ ├── printer
│ ├── Printer.scala
│ ├── PrintingContext.scala
│ ├── RecursivePrinter.scala
│ └── TailPrinter.scala
│ ├── theories
│ ├── ArraysEx.scala
│ ├── Constructors.scala
│ ├── Core.scala
│ ├── FixedSizeBitVectors.scala
│ ├── Ints.scala
│ ├── Operations.scala
│ ├── Reals.scala
│ ├── experimental
│ │ ├── Sets.scala
│ │ └── Strings.scala
│ └── package.scala
│ └── trees
│ ├── TermsOps.scala
│ ├── TreeTransformer.scala
│ ├── Trees.scala
│ └── TreesOps.scala
└── test
└── scala
└── smtlib
├── common
├── BinaryTests.scala
├── HexadecimalTests.scala
├── LinkedListTests.scala
└── SynchronousPipedReader.scala
├── lexer
└── LexerTests.scala
├── parser
├── CommandsParserTests.scala
├── CommandsResponsesParserTests.scala
├── ParserTests.scala
├── TermsOpsTests.scala
└── TreesOpsTests.scala
├── printer
└── PrinterTests.scala
└── theories
├── ArraysExTests.scala
├── CoreTests.scala
├── FixedSizeBitVectorsTests.scala
├── IntsTests.scala
├── RealsTests.scala
└── experimental
├── SetsTests.scala
└── StringsTests.scala
/.gitattributes:
--------------------------------------------------------------------------------
1 | src/it/resources/regression/* linguist-vendored
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 |
3 | .*.swp
4 | *~
5 |
6 | .metals
7 |
--------------------------------------------------------------------------------
/.larabot.conf:
--------------------------------------------------------------------------------
1 | commands = [
2 | "sbt -batch +test"
3 | "sbt -batch +it:test"
4 | ]
5 |
--------------------------------------------------------------------------------
/.sbtopts:
--------------------------------------------------------------------------------
1 | -J-Xss256M
2 | -J-Xms1024M
3 | -J-Xmx8G
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | Changelog
2 | =========
3 |
4 |
5 | Current
6 | -------
7 |
8 | * TIP extensions
9 | * Tree Transformers API
10 | * Cross compilation and deployment to Maven Sonatype
11 | * Add standard theory of floating points
12 | * DSL wrapper
13 | * Bug fixes
14 | * Remove erroneous symbol characters
15 | * Positions always maintained
16 |
17 |
18 | v0.2
19 | -----------------------
20 | *Released 9 March 2016*
21 |
22 | * Constructors and extractors for the standard theories (except Floating point) of SMT-LIB 2.5
23 | * Experimental support for non-standardized theories such as Strings and Sets.
24 | * More robust parser and printers.
25 | * Bug fixes, mostly small edge cases and weird symbol names.
26 |
27 |
28 | v0.1
29 | -----------------------
30 | *Released 2 April 2015*
31 |
32 | Initial version of Scala SmtLib.
33 |
34 | * Extensive support for the SMT-LIB language version 2.5
35 | * SMT-LIB expressions represented with a Scala AST
36 | * Parser turn input stream into AST representation
37 | * Printer turn AST representation into an SMT-LIB complient string output
38 | * abstraction layer to communicate with solver processes over their textual input
39 | * Support for Z3 and CVC4
40 | * Scala SMT-LIB is released under the terms of the MIT license.
41 |
42 |
--------------------------------------------------------------------------------
/IDEAS.md:
--------------------------------------------------------------------------------
1 | # Ideas
2 |
3 | ## DSL
4 |
5 | First we would define the notion of an `Emitter` that can
6 | process commands in some way (printing, executing):
7 |
8 | trait Emitter {
9 | def emit(cmd: Command): Unit
10 | }
11 |
12 | trait Interpreter extends Emitter
13 |
14 |
15 | Then most DSL functions would take an implicit emitter:
16 |
17 | def var[A](prefix: String)(implicit emitter: Emitter) = ???
18 |
19 | To actually use the DSL, we need to start from a concrete emitter:
20 |
21 | z3Interpreter.execute(implicit z3 => {
22 | val x = var[Int]("x")
23 | val y = var[Int]("y")
24 | assert(x < y)
25 | })
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013-2015 Regis Blanc
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/ROADMAP.md:
--------------------------------------------------------------------------------
1 | Road Map
2 | ========
3 |
4 | A list of features potentially useful to add.
5 |
6 | * Type checking of the input script: Make sure the logic declaration corresponds to the syntax of the formulas,
7 | check correct syntax of terms and proper declaration of all uninterpreted symbols used.
8 | * Explore asynchrous IO: Doesn't seem to make sense with a tree sturcture, and script are short in practice.
9 | * Modularize the background theory definitions as an abstract component that could be extended by third party
10 | code. Should only provide the Core theory and the basic theories defined by SMT-LIB standard.
11 | * Explore possible usage of string interpolation to build smtlib scripts
12 |
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
1 | # TODO
2 |
3 | A list of next step tasks.
4 |
5 | * Write unit tests for TIP extension (Tons of Inductive Problems).
6 | * Implement the new floating point standard theory.
7 |
--------------------------------------------------------------------------------
/build.sbt:
--------------------------------------------------------------------------------
1 | enablePlugins(GitVersioning)
2 |
3 | git.useGitDescribe := true
4 |
5 | scalacOptions ++= Seq("-unchecked", "-deprecation", "-feature")
6 |
7 | scalacOptions ++= {
8 | val Seq(_, major, minor) = (scalaVersion in ThisBuild).value.split("\\.").toSeq.map(_.toInt)
9 | if (major <= 10 || (major == 11 && minor < 5)) Seq.empty
10 | else Seq("-Ypatmat-exhaust-depth", "40")
11 | }
12 |
13 | javaOptions in IntegrationTest ++= Seq("-Xss128M")
14 |
15 | fork in IntegrationTest := true
16 |
17 | libraryDependencies += "org.scalatest" %% "scalatest" % "3.1.0-RC3" % "test"
18 |
19 | logBuffered in IntegrationTest := false
20 |
21 | parallelExecution in Test := true
22 |
23 | lazy val commonSettings = Seq(
24 | organization := "com.regblanc",
25 | name := "scala-smtlib",
26 | scalaVersion := "2.13.1",
27 | crossScalaVersions := Seq("2.10.4", "2.11.8", "2.12.1", "2.13.1")
28 | )
29 |
30 | lazy val root = (project in file(".")).
31 | configs(IntegrationTest).
32 | settings(commonSettings: _*).
33 | settings(Defaults.itSettings: _*)
34 |
35 | publishMavenStyle := true
36 |
37 | publishArtifact in Test := false
38 |
39 | publishTo := {
40 | val nexus = "https://oss.sonatype.org/"
41 | if(version.value.trim.endsWith("SNAPSHOT"))
42 | Some("snapshots" at nexus + "content/repositories/snapshots")
43 | else
44 | Some("releases" at nexus + "service/local/staging/deploy/maven2")
45 | }
46 |
47 | pomIncludeRepository := { _ => false }
48 |
49 | licenses := Seq("MIT-style" -> url("https://opensource.org/licenses/MIT"))
50 |
51 | pomExtra := (
52 | https://github.com/regb/scala-smtlib
53 |
54 |
55 | reg
56 | Regis Blanc
57 | http://regblanc.com
58 |
59 |
60 | )
61 |
--------------------------------------------------------------------------------
/project/build.properties:
--------------------------------------------------------------------------------
1 | sbt.version=1.6.2
2 |
--------------------------------------------------------------------------------
/project/plugins.sbt:
--------------------------------------------------------------------------------
1 | addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "1.0.0")
2 |
--------------------------------------------------------------------------------
/src/it/resources/regression/smtlib/parsing/eq_diamond50.smt2:
--------------------------------------------------------------------------------
1 | (set-option :print-success true)
2 | (set-logic QF_UF)
3 | (set-info :source |
4 | Generating minimum transitivity constraints in P-time for deciding Equality Logic,
5 | Ofer Strichman and Mirron Rozanov,
6 | SMT Workshop 2005.
7 |
8 | Translator: Leonardo de Moura. |)
9 | (set-info :smt-lib-version 2.0)
10 | (set-info :category "crafted")
11 | (set-info :status unsat)
12 | (declare-sort U 0)
13 | (declare-fun x0 () U)
14 | (declare-fun y0 () U)
15 | (declare-fun z0 () U)
16 | (declare-fun x1 () U)
17 | (declare-fun y1 () U)
18 | (declare-fun z1 () U)
19 | (declare-fun x2 () U)
20 | (declare-fun y2 () U)
21 | (declare-fun z2 () U)
22 | (declare-fun x3 () U)
23 | (declare-fun y3 () U)
24 | (declare-fun z3 () U)
25 | (declare-fun x4 () U)
26 | (declare-fun y4 () U)
27 | (declare-fun z4 () U)
28 | (declare-fun x5 () U)
29 | (declare-fun y5 () U)
30 | (declare-fun z5 () U)
31 | (declare-fun x6 () U)
32 | (declare-fun y6 () U)
33 | (declare-fun z6 () U)
34 | (declare-fun x7 () U)
35 | (declare-fun y7 () U)
36 | (declare-fun z7 () U)
37 | (declare-fun x8 () U)
38 | (declare-fun y8 () U)
39 | (declare-fun z8 () U)
40 | (declare-fun x9 () U)
41 | (declare-fun y9 () U)
42 | (declare-fun z9 () U)
43 | (declare-fun x10 () U)
44 | (declare-fun y10 () U)
45 | (declare-fun z10 () U)
46 | (declare-fun x11 () U)
47 | (declare-fun y11 () U)
48 | (declare-fun z11 () U)
49 | (declare-fun x12 () U)
50 | (declare-fun y12 () U)
51 | (declare-fun z12 () U)
52 | (declare-fun x13 () U)
53 | (declare-fun y13 () U)
54 | (declare-fun z13 () U)
55 | (declare-fun x14 () U)
56 | (declare-fun y14 () U)
57 | (declare-fun z14 () U)
58 | (declare-fun x15 () U)
59 | (declare-fun y15 () U)
60 | (declare-fun z15 () U)
61 | (declare-fun x16 () U)
62 | (declare-fun y16 () U)
63 | (declare-fun z16 () U)
64 | (declare-fun x17 () U)
65 | (declare-fun y17 () U)
66 | (declare-fun z17 () U)
67 | (declare-fun x18 () U)
68 | (declare-fun y18 () U)
69 | (declare-fun z18 () U)
70 | (declare-fun x19 () U)
71 | (declare-fun y19 () U)
72 | (declare-fun z19 () U)
73 | (declare-fun x20 () U)
74 | (declare-fun y20 () U)
75 | (declare-fun z20 () U)
76 | (declare-fun x21 () U)
77 | (declare-fun y21 () U)
78 | (declare-fun z21 () U)
79 | (declare-fun x22 () U)
80 | (declare-fun y22 () U)
81 | (declare-fun z22 () U)
82 | (declare-fun x23 () U)
83 | (declare-fun y23 () U)
84 | (declare-fun z23 () U)
85 | (declare-fun x24 () U)
86 | (declare-fun y24 () U)
87 | (declare-fun z24 () U)
88 | (declare-fun x25 () U)
89 | (declare-fun y25 () U)
90 | (declare-fun z25 () U)
91 | (declare-fun x26 () U)
92 | (declare-fun y26 () U)
93 | (declare-fun z26 () U)
94 | (declare-fun x27 () U)
95 | (declare-fun y27 () U)
96 | (declare-fun z27 () U)
97 | (declare-fun x28 () U)
98 | (declare-fun y28 () U)
99 | (declare-fun z28 () U)
100 | (declare-fun x29 () U)
101 | (declare-fun y29 () U)
102 | (declare-fun z29 () U)
103 | (declare-fun x30 () U)
104 | (declare-fun y30 () U)
105 | (declare-fun z30 () U)
106 | (declare-fun x31 () U)
107 | (declare-fun y31 () U)
108 | (declare-fun z31 () U)
109 | (declare-fun x32 () U)
110 | (declare-fun y32 () U)
111 | (declare-fun z32 () U)
112 | (declare-fun x33 () U)
113 | (declare-fun y33 () U)
114 | (declare-fun z33 () U)
115 | (declare-fun x34 () U)
116 | (declare-fun y34 () U)
117 | (declare-fun z34 () U)
118 | (declare-fun x35 () U)
119 | (declare-fun y35 () U)
120 | (declare-fun z35 () U)
121 | (declare-fun x36 () U)
122 | (declare-fun y36 () U)
123 | (declare-fun z36 () U)
124 | (declare-fun x37 () U)
125 | (declare-fun y37 () U)
126 | (declare-fun z37 () U)
127 | (declare-fun x38 () U)
128 | (declare-fun y38 () U)
129 | (declare-fun z38 () U)
130 | (declare-fun x39 () U)
131 | (declare-fun y39 () U)
132 | (declare-fun z39 () U)
133 | (declare-fun x40 () U)
134 | (declare-fun y40 () U)
135 | (declare-fun z40 () U)
136 | (declare-fun x41 () U)
137 | (declare-fun y41 () U)
138 | (declare-fun z41 () U)
139 | (declare-fun x42 () U)
140 | (declare-fun y42 () U)
141 | (declare-fun z42 () U)
142 | (declare-fun x43 () U)
143 | (declare-fun y43 () U)
144 | (declare-fun z43 () U)
145 | (declare-fun x44 () U)
146 | (declare-fun y44 () U)
147 | (declare-fun z44 () U)
148 | (declare-fun x45 () U)
149 | (declare-fun y45 () U)
150 | (declare-fun z45 () U)
151 | (declare-fun x46 () U)
152 | (declare-fun y46 () U)
153 | (declare-fun z46 () U)
154 | (declare-fun x47 () U)
155 | (declare-fun y47 () U)
156 | (declare-fun z47 () U)
157 | (declare-fun x48 () U)
158 | (declare-fun y48 () U)
159 | (declare-fun z48 () U)
160 | (declare-fun x49 () U)
161 | (declare-fun y49 () U)
162 | (declare-fun z49 () U)
163 | (assert (and (or (and (= x0 y0) (= y0 x1)) (and (= x0 z0) (= z0 x1))) (or (and (= x1 y1) (= y1 x2)) (and (= x1 z1) (= z1 x2))) (or (and (= x2 y2) (= y2 x3)) (and (= x2 z2) (= z2 x3))) (or (and (= x3 y3) (= y3 x4)) (and (= x3 z3) (= z3 x4))) (or (and (= x4 y4) (= y4 x5)) (and (= x4 z4) (= z4 x5))) (or (and (= x5 y5) (= y5 x6)) (and (= x5 z5) (= z5 x6))) (or (and (= x6 y6) (= y6 x7)) (and (= x6 z6) (= z6 x7))) (or (and (= x7 y7) (= y7 x8)) (and (= x7 z7) (= z7 x8))) (or (and (= x8 y8) (= y8 x9)) (and (= x8 z8) (= z8 x9))) (or (and (= x9 y9) (= y9 x10)) (and (= x9 z9) (= z9 x10))) (or (and (= x10 y10) (= y10 x11)) (and (= x10 z10) (= z10 x11))) (or (and (= x11 y11) (= y11 x12)) (and (= x11 z11) (= z11 x12))) (or (and (= x12 y12) (= y12 x13)) (and (= x12 z12) (= z12 x13))) (or (and (= x13 y13) (= y13 x14)) (and (= x13 z13) (= z13 x14))) (or (and (= x14 y14) (= y14 x15)) (and (= x14 z14) (= z14 x15))) (or (and (= x15 y15) (= y15 x16)) (and (= x15 z15) (= z15 x16))) (or (and (= x16 y16) (= y16 x17)) (and (= x16 z16) (= z16 x17))) (or (and (= x17 y17) (= y17 x18)) (and (= x17 z17) (= z17 x18))) (or (and (= x18 y18) (= y18 x19)) (and (= x18 z18) (= z18 x19))) (or (and (= x19 y19) (= y19 x20)) (and (= x19 z19) (= z19 x20))) (or (and (= x20 y20) (= y20 x21)) (and (= x20 z20) (= z20 x21))) (or (and (= x21 y21) (= y21 x22)) (and (= x21 z21) (= z21 x22))) (or (and (= x22 y22) (= y22 x23)) (and (= x22 z22) (= z22 x23))) (or (and (= x23 y23) (= y23 x24)) (and (= x23 z23) (= z23 x24))) (or (and (= x24 y24) (= y24 x25)) (and (= x24 z24) (= z24 x25))) (or (and (= x25 y25) (= y25 x26)) (and (= x25 z25) (= z25 x26))) (or (and (= x26 y26) (= y26 x27)) (and (= x26 z26) (= z26 x27))) (or (and (= x27 y27) (= y27 x28)) (and (= x27 z27) (= z27 x28))) (or (and (= x28 y28) (= y28 x29)) (and (= x28 z28) (= z28 x29))) (or (and (= x29 y29) (= y29 x30)) (and (= x29 z29) (= z29 x30))) (or (and (= x30 y30) (= y30 x31)) (and (= x30 z30) (= z30 x31))) (or (and (= x31 y31) (= y31 x32)) (and (= x31 z31) (= z31 x32))) (or (and (= x32 y32) (= y32 x33)) (and (= x32 z32) (= z32 x33))) (or (and (= x33 y33) (= y33 x34)) (and (= x33 z33) (= z33 x34))) (or (and (= x34 y34) (= y34 x35)) (and (= x34 z34) (= z34 x35))) (or (and (= x35 y35) (= y35 x36)) (and (= x35 z35) (= z35 x36))) (or (and (= x36 y36) (= y36 x37)) (and (= x36 z36) (= z36 x37))) (or (and (= x37 y37) (= y37 x38)) (and (= x37 z37) (= z37 x38))) (or (and (= x38 y38) (= y38 x39)) (and (= x38 z38) (= z38 x39))) (or (and (= x39 y39) (= y39 x40)) (and (= x39 z39) (= z39 x40))) (or (and (= x40 y40) (= y40 x41)) (and (= x40 z40) (= z40 x41))) (or (and (= x41 y41) (= y41 x42)) (and (= x41 z41) (= z41 x42))) (or (and (= x42 y42) (= y42 x43)) (and (= x42 z42) (= z42 x43))) (or (and (= x43 y43) (= y43 x44)) (and (= x43 z43) (= z43 x44))) (or (and (= x44 y44) (= y44 x45)) (and (= x44 z44) (= z44 x45))) (or (and (= x45 y45) (= y45 x46)) (and (= x45 z45) (= z45 x46))) (or (and (= x46 y46) (= y46 x47)) (and (= x46 z46) (= z46 x47))) (or (and (= x47 y47) (= y47 x48)) (and (= x47 z47) (= z47 x48))) (or (and (= x48 y48) (= y48 x49)) (and (= x48 z48) (= z48 x49))) (not (= x0 x49))))
164 | (check-sat)
165 | (exit)
166 |
--------------------------------------------------------------------------------
/src/it/resources/regression/smtlib/solving/all/PEQ012_size3.smt2:
--------------------------------------------------------------------------------
1 | (set-option :print-success true)
2 | (set-logic QF_UF)
3 | (set-info :source |
4 | CADE ATP System competition. See http://www.cs.miami.edu/~tptp/CASC
5 | for more information.
6 |
7 | This benchmark was obtained by trying to find a finite model of a first-order
8 | formula (Albert Oliveras).
9 | |)
10 | (set-info :smt-lib-version 2.0)
11 | (set-info :category "crafted")
12 | (set-info :status unsat)
13 | (declare-sort U 0)
14 | (declare-fun f1 (U U) U)
15 | (declare-fun c6 () U)
16 | (declare-fun c3 () U)
17 | (declare-fun c7 () U)
18 | (declare-fun c5 () U)
19 | (declare-fun c2 () U)
20 | (declare-fun c4 () U)
21 | (declare-fun c8 () U)
22 | (declare-fun c9 () U)
23 | (declare-fun c_0 () U)
24 | (declare-fun c_1 () U)
25 | (declare-fun c_2 () U)
26 | (assert (let ((?v_0 (f1 c_0 c_0)) (?v_2 (= c_0 c_0))) (let ((?v_18 (or (not (= ?v_0 ?v_0)) ?v_2)) (?v_6 (f1 c_1 c_0)) (?v_3 (= c_0 c_1)) (?v_7 (f1 c_2 c_0)) (?v_4 (= c_0 c_2)) (?v_1 (f1 c_0 c_1))) (let ((?v_19 (not (= ?v_1 ?v_1))) (?v_8 (f1 c_1 c_1)) (?v_11 (f1 c_2 c_1)) (?v_5 (f1 c_0 c_2))) (let ((?v_20 (not (= ?v_5 ?v_5))) (?v_13 (f1 c_1 c_2)) (?v_14 (f1 c_2 c_2)) (?v_9 (= c_1 c_0)) (?v_21 (not (= ?v_6 ?v_6))) (?v_10 (= c_1 c_1)) (?v_12 (= c_1 c_2))) (let ((?v_22 (or (not (= ?v_8 ?v_8)) ?v_10)) (?v_23 (not (= ?v_13 ?v_13))) (?v_15 (= c_2 c_0)) (?v_16 (= c_2 c_1)) (?v_24 (not (= ?v_7 ?v_7))) (?v_17 (= c_2 c_2)) (?v_25 (not (= ?v_11 ?v_11)))) (let ((?v_26 (or (not (= ?v_14 ?v_14)) ?v_17)) (?v_27 (f1 c_0 ?v_0)) (?v_34 (f1 c_0 ?v_1)) (?v_40 (f1 c_0 ?v_5)) (?v_33 (f1 c_0 ?v_6)) (?v_51 (f1 c_0 ?v_8)) (?v_58 (f1 c_0 ?v_13)) (?v_39 (f1 c_0 ?v_7)) (?v_57 (f1 c_0 ?v_11)) (?v_75 (f1 c_0 ?v_14)) (?v_29 (f1 c_1 ?v_0)) (?v_36 (f1 c_1 ?v_1)) (?v_42 (f1 c_1 ?v_5)) (?v_35 (f1 c_1 ?v_6)) (?v_53 (f1 c_1 ?v_8)) (?v_60 (f1 c_1 ?v_13)) (?v_41 (f1 c_1 ?v_7)) (?v_59 (f1 c_1 ?v_11)) (?v_77 (f1 c_1 ?v_14)) (?v_31 (f1 c_2 ?v_0)) (?v_38 (f1 c_2 ?v_1)) (?v_44 (f1 c_2 ?v_5)) (?v_37 (f1 c_2 ?v_6)) (?v_55 (f1 c_2 ?v_8)) (?v_62 (f1 c_2 ?v_13)) (?v_43 (f1 c_2 ?v_7)) (?v_61 (f1 c_2 ?v_11)) (?v_79 (f1 c_2 ?v_14))) (let ((?v_28 (f1 c_0 (f1 c_0 ?v_27))) (?v_30 (f1 c_0 (f1 c_0 ?v_29))) (?v_32 (f1 c_0 (f1 c_0 ?v_31))) (?v_46 (f1 c_0 (f1 c_1 ?v_33))) (?v_45 (f1 c_1 (f1 c_0 ?v_34))) (?v_48 (f1 c_0 (f1 c_1 ?v_35))) (?v_47 (f1 c_1 (f1 c_0 ?v_36))) (?v_50 (f1 c_0 (f1 c_1 ?v_37))) (?v_49 (f1 c_1 (f1 c_0 ?v_38))) (?v_64 (f1 c_0 (f1 c_2 ?v_39))) (?v_63 (f1 c_2 (f1 c_0 ?v_40))) (?v_66 (f1 c_0 (f1 c_2 ?v_41))) (?v_65 (f1 c_2 (f1 c_0 ?v_42))) (?v_68 (f1 c_0 (f1 c_2 ?v_43))) (?v_67 (f1 c_2 (f1 c_0 ?v_44))) (?v_52 (f1 c_1 (f1 c_1 ?v_51))) (?v_54 (f1 c_1 (f1 c_1 ?v_53))) (?v_56 (f1 c_1 (f1 c_1 ?v_55))) (?v_70 (f1 c_1 (f1 c_2 ?v_57))) (?v_69 (f1 c_2 (f1 c_1 ?v_58))) (?v_72 (f1 c_1 (f1 c_2 ?v_59))) (?v_71 (f1 c_2 (f1 c_1 ?v_60))) (?v_74 (f1 c_1 (f1 c_2 ?v_61))) (?v_73 (f1 c_2 (f1 c_1 ?v_62))) (?v_76 (f1 c_2 (f1 c_2 ?v_75))) (?v_78 (f1 c_2 (f1 c_2 ?v_77))) (?v_80 (f1 c_2 (f1 c_2 ?v_79)))) (and (distinct c_0 c_1 c_2) ?v_18 (or (not (= ?v_0 ?v_6)) ?v_3) (or (not (= ?v_0 ?v_7)) ?v_4) (or ?v_19 ?v_2) (or (not (= ?v_1 ?v_8)) ?v_3) (or (not (= ?v_1 ?v_11)) ?v_4) (or ?v_20 ?v_2) (or (not (= ?v_5 ?v_13)) ?v_3) (or (not (= ?v_5 ?v_14)) ?v_4) (or (not (= ?v_6 ?v_0)) ?v_9) (or ?v_21 ?v_10) (or (not (= ?v_6 ?v_7)) ?v_12) (or (not (= ?v_8 ?v_1)) ?v_9) ?v_22 (or (not (= ?v_8 ?v_11)) ?v_12) (or (not (= ?v_13 ?v_5)) ?v_9) (or ?v_23 ?v_10) (or (not (= ?v_13 ?v_14)) ?v_12) (or (not (= ?v_7 ?v_0)) ?v_15) (or (not (= ?v_7 ?v_6)) ?v_16) (or ?v_24 ?v_17) (or (not (= ?v_11 ?v_1)) ?v_15) (or (not (= ?v_11 ?v_8)) ?v_16) (or ?v_25 ?v_17) (or (not (= ?v_14 ?v_5)) ?v_15) (or (not (= ?v_14 ?v_13)) ?v_16) ?v_26 ?v_18 (or (not (= ?v_0 ?v_1)) ?v_3) (or (not (= ?v_0 ?v_5)) ?v_4) (or (not (= ?v_1 ?v_0)) ?v_9) (or ?v_19 ?v_10) (or (not (= ?v_1 ?v_5)) ?v_12) (or (not (= ?v_5 ?v_0)) ?v_15) (or (not (= ?v_5 ?v_1)) ?v_16) (or ?v_20 ?v_17) (or ?v_21 ?v_2) (or (not (= ?v_6 ?v_8)) ?v_3) (or (not (= ?v_6 ?v_13)) ?v_4) (or (not (= ?v_8 ?v_6)) ?v_9) ?v_22 (or (not (= ?v_8 ?v_13)) ?v_12) (or (not (= ?v_13 ?v_6)) ?v_15) (or (not (= ?v_13 ?v_8)) ?v_16) (or ?v_23 ?v_17) (or ?v_24 ?v_2) (or (not (= ?v_7 ?v_11)) ?v_3) (or (not (= ?v_7 ?v_14)) ?v_4) (or (not (= ?v_11 ?v_7)) ?v_9) (or ?v_25 ?v_10) (or (not (= ?v_11 ?v_14)) ?v_12) (or (not (= ?v_14 ?v_7)) ?v_15) (or (not (= ?v_14 ?v_11)) ?v_16) ?v_26 (= (f1 ?v_0 c_0) ?v_27) (= (f1 ?v_0 c_1) ?v_34) (= (f1 ?v_0 c_2) ?v_40) (= (f1 ?v_1 c_0) ?v_33) (= (f1 ?v_1 c_1) ?v_51) (= (f1 ?v_1 c_2) ?v_58) (= (f1 ?v_5 c_0) ?v_39) (= (f1 ?v_5 c_1) ?v_57) (= (f1 ?v_5 c_2) ?v_75) (= (f1 ?v_6 c_0) ?v_29) (= (f1 ?v_6 c_1) ?v_36) (= (f1 ?v_6 c_2) ?v_42) (= (f1 ?v_8 c_0) ?v_35) (= (f1 ?v_8 c_1) ?v_53) (= (f1 ?v_8 c_2) ?v_60) (= (f1 ?v_13 c_0) ?v_41) (= (f1 ?v_13 c_1) ?v_59) (= (f1 ?v_13 c_2) ?v_77) (= (f1 ?v_7 c_0) ?v_31) (= (f1 ?v_7 c_1) ?v_38) (= (f1 ?v_7 c_2) ?v_44) (= (f1 ?v_11 c_0) ?v_37) (= (f1 ?v_11 c_1) ?v_55) (= (f1 ?v_11 c_2) ?v_62) (= (f1 ?v_14 c_0) ?v_43) (= (f1 ?v_14 c_1) ?v_61) (= (f1 ?v_14 c_2) ?v_79) (= ?v_28 ?v_28) (= ?v_30 ?v_30) (= ?v_32 ?v_32) (= ?v_46 ?v_45) (= ?v_48 ?v_47) (= ?v_50 ?v_49) (= ?v_64 ?v_63) (= ?v_66 ?v_65) (= ?v_68 ?v_67) (= ?v_45 ?v_46) (= ?v_47 ?v_48) (= ?v_49 ?v_50) (= ?v_52 ?v_52) (= ?v_54 ?v_54) (= ?v_56 ?v_56) (= ?v_70 ?v_69) (= ?v_72 ?v_71) (= ?v_74 ?v_73) (= ?v_63 ?v_64) (= ?v_65 ?v_66) (= ?v_67 ?v_68) (= ?v_69 ?v_70) (= ?v_71 ?v_72) (= ?v_73 ?v_74) (= ?v_76 ?v_76) (= ?v_78 ?v_78) (= ?v_80 ?v_80) (= (f1 c6 c3) (f1 c7 c5)) (= (f1 c2 c3) (f1 c4 c5)) (= (f1 c2 c8) (f1 c4 c9)) (not (= (f1 c6 c8) (f1 c7 c9))) (or (= ?v_0 c_0) (= ?v_0 c_1) (= ?v_0 c_2)) (or (= ?v_1 c_0) (= ?v_1 c_1) (= ?v_1 c_2)) (or (= ?v_5 c_0) (= ?v_5 c_1) (= ?v_5 c_2)) (or (= ?v_6 c_0) (= ?v_6 c_1) (= ?v_6 c_2)) (or (= ?v_8 c_0) (= ?v_8 c_1) (= ?v_8 c_2)) (or (= ?v_13 c_0) (= ?v_13 c_1) (= ?v_13 c_2)) (or (= ?v_7 c_0) (= ?v_7 c_1) (= ?v_7 c_2)) (or (= ?v_11 c_0) (= ?v_11 c_1) (= ?v_11 c_2)) (or (= ?v_14 c_0) (= ?v_14 c_1) (= ?v_14 c_2)) (or (= c6 c_0) (= c6 c_1) (= c6 c_2)) (or (= c3 c_0) (= c3 c_1) (= c3 c_2)) (or (= c7 c_0) (= c7 c_1) (= c7 c_2)) (or (= c5 c_0) (= c5 c_1) (= c5 c_2)) (or (= c2 c_0) (= c2 c_1) (= c2 c_2)) (or (= c4 c_0) (= c4 c_1) (= c4 c_2)) (or (= c8 c_0) (= c8 c_1) (= c8 c_2)) (or (= c9 c_0) (= c9 c_1) (= c9 c_2)))))))))))
27 | (check-sat)
28 | (exit)
29 |
--------------------------------------------------------------------------------
/src/it/resources/regression/smtlib/solving/all/a20test0001.smt2:
--------------------------------------------------------------------------------
1 | (set-option :print-success true)
2 | (set-logic QF_ABV)
3 | (set-info :source |
4 | Bit-vector benchmarks from Dawson Engler's tool contributed by Vijay Ganesh
5 | (vganesh@stanford.edu). Translated into SMT-LIB format by Clark Barrett using
6 | CVC3. |)
7 | (set-info :smt-lib-version 2.0)
8 | (set-info :category "industrial")
9 | (set-info :status sat)
10 | (declare-fun x () (Array (_ BitVec 32) (_ BitVec 8)))
11 | (declare-fun y () (Array (_ BitVec 32) (_ BitVec 8)))
12 | (assert (= (concat (_ bv0 30) ((_ extract 2 1) (select x (_ bv0 32)))) (_ bv2 32)))
13 | (assert (not (not (= ((_ extract 3 3) (select y (_ bv0 32))) (_ bv0 1)))))
14 | (check-sat)
15 | (exit)
16 |
--------------------------------------------------------------------------------
/src/it/resources/regression/smtlib/solving/all/b159test0001.smt2:
--------------------------------------------------------------------------------
1 | (set-option :print-success true)
2 | (set-logic QF_ABV)
3 | (set-info :source |
4 | Bit-vector benchmarks from Dawson Engler's tool contributed by Vijay Ganesh
5 | (vganesh@stanford.edu). Translated into SMT-LIB format by Clark Barrett using
6 | CVC3. |)
7 | (set-info :smt-lib-version 2.0)
8 | (set-info :category "industrial")
9 | (set-info :status sat)
10 | (declare-fun a () (Array (_ BitVec 32) (_ BitVec 8)))
11 | (assert (bvslt ((_ sign_extend 24) (select a (_ bv1 32))) ((_ sign_extend 24) (select a (_ bv0 32)))))
12 | (assert (let ((?v_0 (store (store a (_ bv1 32) (select a (_ bv0 32))) (_ bv0 32) ((_ extract 7 0) ((_ sign_extend 24) (select a (_ bv1 32))))))) (not (bvslt ((_ sign_extend 24) (select ?v_0 (_ bv2 32))) ((_ sign_extend 24) (select ?v_0 (_ bv1 32)))))))
13 | (assert (let ((?v_0 (store (store a (_ bv1 32) (select a (_ bv0 32))) (_ bv0 32) ((_ extract 7 0) ((_ sign_extend 24) (select a (_ bv1 32))))))) (not (bvslt ((_ sign_extend 24) (select ?v_0 (_ bv3 32))) ((_ sign_extend 24) (select ?v_0 (_ bv2 32)))))))
14 | (check-sat)
15 | (exit)
16 |
--------------------------------------------------------------------------------
/src/it/resources/regression/smtlib/solving/all/cl5_nebula_array_0001.fof.smt2:
--------------------------------------------------------------------------------
1 | (set-option :print-success true)
2 | (set-logic AUFLIRA)
3 | (set-info :source |
4 | NASA benchmarks from "Using Automated Theorem Provers to Certify Auto-generated
5 | Aerospace Software", IJCAR 2004. Translated from TPTP format by Yeting Ge and
6 | Clark Barrett
7 |
8 | |)
9 | (set-info :smt-lib-version 2.0)
10 | (set-info :category "industrial")
11 | (set-info :status unsat)
12 | (declare-fun def () Real)
13 | (declare-fun pv10 () Int)
14 | (declare-fun pv63 () Int)
15 | (declare-fun use () Real)
16 | (declare-fun uniform_int_rnd (Int Int) Int)
17 | (declare-fun abs_ (Real) Real)
18 | (declare-fun log (Real) Real)
19 | (declare-fun exp (Real) Real)
20 | (declare-fun cos (Real) Real)
21 | (declare-fun sin (Real) Real)
22 | (declare-fun sqrt (Real) Real)
23 | (declare-fun divide (Real Real) Real)
24 | (declare-fun cond (Int Real Real) Real)
25 | (declare-fun tptp_term_equal (Real Real) Int)
26 | (declare-fun tptp_term_equals (Real Real) Int)
27 | (declare-fun tptp_term_and (Real Real) Int)
28 | (declare-fun sum (Int Int Real) Real)
29 | (declare-fun dim (Int Int) Int)
30 | (declare-fun trans ((Array Int (Array Int Real))) (Array Int (Array Int Real)))
31 | (declare-fun inv ((Array Int (Array Int Real))) (Array Int (Array Int Real)))
32 | (declare-fun tptp_mmul ((Array Int (Array Int Real)) (Array Int (Array Int Real))) (Array Int (Array Int Real)))
33 | (declare-fun tptp_madd ((Array Int (Array Int Real)) (Array Int (Array Int Real))) (Array Int (Array Int Real)))
34 | (declare-fun tptp_msub ((Array Int (Array Int Real)) (Array Int (Array Int Real))) (Array Int (Array Int Real)))
35 | (declare-fun tptp_const_array1 (Int Real) (Array Int Real))
36 | (declare-fun tptp_const_array2 (Int Int Real) (Array Int (Array Int Real)))
37 | (assert (forall ((?X_0 Int) (?C_1 Int)) (=> (>= ?X_0 0) (<= (uniform_int_rnd ?C_1 ?X_0) ?X_0))))
38 | (assert (forall ((?X_2 Int) (?C_3 Int)) (=> (>= ?X_2 0) (>= (uniform_int_rnd ?C_3 ?X_2) 0))))
39 | (assert (forall ((?I_4 Int) (?L_5 Int) (?U_6 Int) (?Val_7 Real)) (=> (and (<= ?L_5 ?I_4) (<= ?I_4 ?U_6)) (= (select (tptp_const_array1 (dim ?L_5 ?U_6) ?Val_7) ?I_4) ?Val_7))))
40 | (assert (forall ((?I_8 Int) (?L1_9 Int) (?U1_10 Int) (?J_11 Int) (?L2_12 Int) (?U2_13 Int) (?Val_14 Real)) (=> (and (and (and (<= ?L1_9 ?I_8) (<= ?I_8 ?U1_10)) (<= ?L2_12 ?J_11)) (<= ?J_11 ?U2_13)) (= (select (select (tptp_const_array2 (dim ?L1_9 ?U1_10) (dim ?L2_12 ?U2_13) ?Val_14) ?I_8) ?J_11) ?Val_14))))
41 | (assert (forall ((?I0_15 Int) (?J0_16 Int) (?A_17 (Array Int (Array Int Real))) (?B_18 (Array Int (Array Int Real))) (?N_19 Int)) (let ((?v_0 (tptp_mmul ?A_17 (tptp_mmul ?B_18 (trans ?A_17))))) (=> (and (and (and (and (>= ?I0_15 0) (<= ?I0_15 ?N_19)) (>= ?J0_16 0)) (<= ?J0_16 ?N_19)) (= (select (select ?B_18 ?I0_15) ?J0_16) (select (select ?B_18 ?J0_16) ?I0_15))) (= (select (select ?v_0 ?I0_15) ?J0_16) (select (select ?v_0 ?J0_16) ?I0_15))))))
42 | (assert (forall ((?I0_20 Int) (?J0_21 Int) (?I_22 Int) (?J_23 Int) (?A_24 (Array Int (Array Int Real))) (?B_25 (Array Int (Array Int Real))) (?N_26 Int) (?M_27 Int)) (let ((?v_0 (tptp_mmul ?A_24 (tptp_mmul ?B_25 (trans ?A_24))))) (=> (and (and (and (and (and (and (and (and (>= ?I0_20 0) (<= ?I0_20 ?N_26)) (>= ?J0_21 0)) (<= ?J0_21 ?N_26)) (>= ?I_22 0)) (<= ?I_22 ?M_27)) (>= ?J_23 0)) (<= ?J_23 ?M_27)) (= (select (select ?B_25 ?I_22) ?J_23) (select (select ?B_25 ?J_23) ?I_22))) (= (select (select ?v_0 ?I0_20) ?J0_21) (select (select ?v_0 ?J0_21) ?I0_20))))))
43 | (assert (forall ((?I_28 Int) (?J_29 Int) (?A_30 (Array Int (Array Int Real))) (?B_31 (Array Int (Array Int Real))) (?N_32 Int)) (let ((?v_0 (tptp_madd ?A_30 ?B_31))) (=> (and (and (and (and (and (>= ?I_28 0) (<= ?I_28 ?N_32)) (>= ?J_29 0)) (<= ?J_29 ?N_32)) (= (select (select ?A_30 ?I_28) ?J_29) (select (select ?A_30 ?J_29) ?I_28))) (= (select (select ?B_31 ?I_28) ?J_29) (select (select ?B_31 ?J_29) ?I_28))) (= (select (select ?v_0 ?I_28) ?J_29) (select (select ?v_0 ?J_29) ?I_28))))))
44 | (assert (forall ((?I_33 Int) (?J_34 Int) (?A_35 (Array Int (Array Int Real))) (?B_36 (Array Int (Array Int Real))) (?N_37 Int)) (let ((?v_0 (tptp_msub ?A_35 ?B_36))) (=> (and (and (and (and (and (>= ?I_33 0) (<= ?I_33 ?N_37)) (>= ?J_34 0)) (<= ?J_34 ?N_37)) (= (select (select ?A_35 ?I_33) ?J_34) (select (select ?A_35 ?J_34) ?I_33))) (= (select (select ?B_36 ?I_33) ?J_34) (select (select ?B_36 ?J_34) ?I_33))) (= (select (select ?v_0 ?I_33) ?J_34) (select (select ?v_0 ?J_34) ?I_33))))))
45 | (assert (forall ((?I_38 Int) (?J_39 Int) (?A_40 (Array Int (Array Int Real))) (?N_41 Int)) (let ((?v_0 (trans ?A_40))) (=> (and (and (and (and (>= ?I_38 0) (<= ?I_38 ?N_41)) (>= ?J_39 0)) (<= ?J_39 ?N_41)) (= (select (select ?A_40 ?I_38) ?J_39) (select (select ?A_40 ?J_39) ?I_38))) (= (select (select ?v_0 ?I_38) ?J_39) (select (select ?v_0 ?J_39) ?I_38))))))
46 | (assert (forall ((?I_42 Int) (?J_43 Int) (?A_44 (Array Int (Array Int Real))) (?N_45 Int)) (let ((?v_0 (inv ?A_44))) (=> (and (and (and (and (>= ?I_42 0) (<= ?I_42 ?N_45)) (>= ?J_43 0)) (<= ?J_43 ?N_45)) (= (select (select ?A_44 ?I_42) ?J_43) (select (select ?A_44 ?J_43) ?I_42))) (= (select (select ?v_0 ?I_42) ?J_43) (select (select ?v_0 ?J_43) ?I_42))))))
47 | (assert (forall ((?I0_46 Int) (?J0_47 Int) (?I_48 Int) (?J_49 Int) (?A_50 (Array Int (Array Int Real))) (?B_51 (Array Int (Array Int Real))) (?C_52 (Array Int (Array Int Real))) (?D_53 (Array Int (Array Int Real))) (?E_54 (Array Int (Array Int Real))) (?F_55 (Array Int (Array Int Real))) (?N_56 Int) (?M_57 Int)) (let ((?v_0 (tptp_madd ?A_50 (tptp_mmul ?B_51 (tptp_mmul (tptp_madd (tptp_mmul ?C_52 (tptp_mmul ?D_53 (trans ?C_52))) (tptp_mmul ?E_54 (tptp_mmul ?F_55 (trans ?E_54)))) (trans ?B_51)))))) (=> (and (and (and (and (and (and (and (and (and (and (>= ?I0_46 0) (<= ?I0_46 ?N_56)) (>= ?J0_47 0)) (<= ?J0_47 ?N_56)) (>= ?I_48 0)) (<= ?I_48 ?M_57)) (>= ?J_49 0)) (<= ?J_49 ?M_57)) (= (select (select ?D_53 ?I_48) ?J_49) (select (select ?D_53 ?J_49) ?I_48))) (= (select (select ?A_50 ?I0_46) ?J0_47) (select (select ?A_50 ?J0_47) ?I0_46))) (= (select (select ?F_55 ?I0_46) ?J0_47) (select (select ?F_55 ?J0_47) ?I0_46))) (= (select (select ?v_0 ?I0_46) ?J0_47) (select (select ?v_0 ?J0_47) ?I0_46))))))
48 | (assert (forall ((?Body_58 Real)) (= (sum 0 (- 1) ?Body_58) 0.0)))
49 | (assert (not (= def use)))
50 | (assert (not (=> (and (and (and (>= pv10 0) (>= pv63 1)) (<= pv10 135299)) (<= pv63 4)) (>= pv63 0))))
51 | (check-sat)
52 | (exit)
53 |
--------------------------------------------------------------------------------
/src/it/resources/regression/smtlib/solving/all/define_fun1.smt2:
--------------------------------------------------------------------------------
1 | (set-option :print-success true)
2 | (set-logic QF_UF)
3 | (declare-sort U 0)
4 | (declare-fun x0 () U)
5 | (declare-fun y0 () U)
6 | (define-fun x1 () U x0)
7 | (define-fun y1 () U y0)
8 | (assert (not (= x1 y1)))
9 | (check-sat)
10 | (exit)
11 |
--------------------------------------------------------------------------------
/src/it/resources/regression/smtlib/solving/all/eq_diamond1.smt2:
--------------------------------------------------------------------------------
1 | (set-option :print-success true)
2 | (set-logic QF_UF)
3 | (set-info :source |
4 | Generating minimum transitivity constraints in P-time for deciding Equality Logic,
5 | Ofer Strichman and Mirron Rozanov,
6 | SMT Workshop 2005.
7 |
8 | Translator: Leonardo de Moura. |)
9 | (set-info :smt-lib-version 2.0)
10 | (set-info :category "crafted")
11 | (set-info :status unsat)
12 | (declare-sort U 0)
13 | (declare-fun x0 () U)
14 | (declare-fun y0 () U)
15 | (declare-fun z0 () U)
16 | (assert (not (= x0 x0)))
17 | (check-sat)
18 | (exit)
19 |
--------------------------------------------------------------------------------
/src/it/resources/regression/smtlib/solving/all/eq_diamond2.smt2:
--------------------------------------------------------------------------------
1 | (set-option :print-success true)
2 | (set-logic QF_UF)
3 | (set-info :source |
4 | Generating minimum transitivity constraints in P-time for deciding Equality Logic,
5 | Ofer Strichman and Mirron Rozanov,
6 | SMT Workshop 2005.
7 |
8 | Translator: Leonardo de Moura. |)
9 | (set-info :smt-lib-version 2.0)
10 | (set-info :category "crafted")
11 | (set-info :status unsat)
12 | (declare-sort U 0)
13 | (declare-fun x0 () U)
14 | (declare-fun y0 () U)
15 | (declare-fun z0 () U)
16 | (declare-fun x1 () U)
17 | (declare-fun y1 () U)
18 | (declare-fun z1 () U)
19 | (assert (and (or (and (= x0 y0) (= y0 x1)) (and (= x0 z0) (= z0 x1))) (not (= x0 x1))))
20 | (check-sat)
21 | (exit)
22 |
--------------------------------------------------------------------------------
/src/it/resources/regression/smtlib/solving/all/eq_diamond3.smt2:
--------------------------------------------------------------------------------
1 | (set-option :print-success true)
2 | (set-logic QF_UF)
3 | (set-info :source |
4 | Generating minimum transitivity constraints in P-time for deciding Equality Logic,
5 | Ofer Strichman and Mirron Rozanov,
6 | SMT Workshop 2005.
7 |
8 | Translator: Leonardo de Moura. |)
9 | (set-info :smt-lib-version 2.0)
10 | (set-info :category "crafted")
11 | (set-info :status unsat)
12 | (declare-sort U 0)
13 | (declare-fun x0 () U)
14 | (declare-fun y0 () U)
15 | (declare-fun z0 () U)
16 | (declare-fun x1 () U)
17 | (declare-fun y1 () U)
18 | (declare-fun z1 () U)
19 | (declare-fun x2 () U)
20 | (declare-fun y2 () U)
21 | (declare-fun z2 () U)
22 | (assert (and (or (and (= x0 y0) (= y0 x1)) (and (= x0 z0) (= z0 x1))) (or (and (= x1 y1) (= y1 x2)) (and (= x1 z1) (= z1 x2))) (not (= x0 x2))))
23 | (check-sat)
24 | (exit)
25 |
--------------------------------------------------------------------------------
/src/it/resources/regression/smtlib/solving/all/quaternion_ds1_symm_0818.fof.smt2:
--------------------------------------------------------------------------------
1 | (set-option :print-success true)
2 | (set-logic AUFLIRA)
3 | (set-info :source |
4 | NASA benchmarks from "Using Automated Theorem Provers to Certify Auto-generated
5 | Aerospace Software", IJCAR 2004. Translated from TPTP format by Yeting Ge and
6 | Clark Barrett
7 |
8 | |)
9 | (set-info :smt-lib-version 2.0)
10 | (set-info :category "industrial")
11 | (set-info :status unsat)
12 | (declare-fun def () Real)
13 | (declare-fun q_ds1_filter () (Array Int (Array Int Real)))
14 | (declare-fun r_ds1_filter () (Array Int (Array Int Real)))
15 | (declare-fun use () Real)
16 | (declare-fun xinit_noise () (Array Int Real))
17 | (declare-fun uniform_int_rnd (Int Int) Int)
18 | (declare-fun abs_ (Real) Real)
19 | (declare-fun log (Real) Real)
20 | (declare-fun exp (Real) Real)
21 | (declare-fun cos (Real) Real)
22 | (declare-fun sin (Real) Real)
23 | (declare-fun sqrt (Real) Real)
24 | (declare-fun divide (Real Real) Real)
25 | (declare-fun cond (Int Real Real) Real)
26 | (declare-fun tptp_term_equal (Real Real) Int)
27 | (declare-fun tptp_term_equals (Real Real) Int)
28 | (declare-fun tptp_term_and (Real Real) Int)
29 | (declare-fun sum (Int Int Real) Real)
30 | (declare-fun dim (Int Int) Int)
31 | (declare-fun trans ((Array Int (Array Int Real))) (Array Int (Array Int Real)))
32 | (declare-fun inv ((Array Int (Array Int Real))) (Array Int (Array Int Real)))
33 | (declare-fun tptp_mmul ((Array Int (Array Int Real)) (Array Int (Array Int Real))) (Array Int (Array Int Real)))
34 | (declare-fun tptp_madd ((Array Int (Array Int Real)) (Array Int (Array Int Real))) (Array Int (Array Int Real)))
35 | (declare-fun tptp_msub ((Array Int (Array Int Real)) (Array Int (Array Int Real))) (Array Int (Array Int Real)))
36 | (declare-fun tptp_const_array1 (Int Real) (Array Int Real))
37 | (declare-fun tptp_const_array2 (Int Int Real) (Array Int (Array Int Real)))
38 | (assert (forall ((?X_0 Int) (?C_1 Int)) (=> (>= ?X_0 0) (<= (uniform_int_rnd ?C_1 ?X_0) ?X_0))))
39 | (assert (forall ((?X_2 Int) (?C_3 Int)) (=> (>= ?X_2 0) (>= (uniform_int_rnd ?C_3 ?X_2) 0))))
40 | (assert (forall ((?I_4 Int) (?L_5 Int) (?U_6 Int) (?Val_7 Real)) (=> (and (<= ?L_5 ?I_4) (<= ?I_4 ?U_6)) (= (select (tptp_const_array1 (dim ?L_5 ?U_6) ?Val_7) ?I_4) ?Val_7))))
41 | (assert (forall ((?I_8 Int) (?L1_9 Int) (?U1_10 Int) (?J_11 Int) (?L2_12 Int) (?U2_13 Int) (?Val_14 Real)) (=> (and (and (and (<= ?L1_9 ?I_8) (<= ?I_8 ?U1_10)) (<= ?L2_12 ?J_11)) (<= ?J_11 ?U2_13)) (= (select (select (tptp_const_array2 (dim ?L1_9 ?U1_10) (dim ?L2_12 ?U2_13) ?Val_14) ?I_8) ?J_11) ?Val_14))))
42 | (assert (forall ((?I0_15 Int) (?J0_16 Int) (?A_17 (Array Int (Array Int Real))) (?B_18 (Array Int (Array Int Real))) (?N_19 Int)) (let ((?v_0 (tptp_mmul ?A_17 (tptp_mmul ?B_18 (trans ?A_17))))) (=> (and (and (and (and (>= ?I0_15 0) (<= ?I0_15 ?N_19)) (>= ?J0_16 0)) (<= ?J0_16 ?N_19)) (= (select (select ?B_18 ?I0_15) ?J0_16) (select (select ?B_18 ?J0_16) ?I0_15))) (= (select (select ?v_0 ?I0_15) ?J0_16) (select (select ?v_0 ?J0_16) ?I0_15))))))
43 | (assert (forall ((?I0_20 Int) (?J0_21 Int) (?I_22 Int) (?J_23 Int) (?A_24 (Array Int (Array Int Real))) (?B_25 (Array Int (Array Int Real))) (?N_26 Int) (?M_27 Int)) (let ((?v_0 (tptp_mmul ?A_24 (tptp_mmul ?B_25 (trans ?A_24))))) (=> (and (and (and (and (and (and (and (and (>= ?I0_20 0) (<= ?I0_20 ?N_26)) (>= ?J0_21 0)) (<= ?J0_21 ?N_26)) (>= ?I_22 0)) (<= ?I_22 ?M_27)) (>= ?J_23 0)) (<= ?J_23 ?M_27)) (= (select (select ?B_25 ?I_22) ?J_23) (select (select ?B_25 ?J_23) ?I_22))) (= (select (select ?v_0 ?I0_20) ?J0_21) (select (select ?v_0 ?J0_21) ?I0_20))))))
44 | (assert (forall ((?I_28 Int) (?J_29 Int) (?A_30 (Array Int (Array Int Real))) (?B_31 (Array Int (Array Int Real))) (?N_32 Int)) (let ((?v_0 (tptp_madd ?A_30 ?B_31))) (=> (and (and (and (and (and (>= ?I_28 0) (<= ?I_28 ?N_32)) (>= ?J_29 0)) (<= ?J_29 ?N_32)) (= (select (select ?A_30 ?I_28) ?J_29) (select (select ?A_30 ?J_29) ?I_28))) (= (select (select ?B_31 ?I_28) ?J_29) (select (select ?B_31 ?J_29) ?I_28))) (= (select (select ?v_0 ?I_28) ?J_29) (select (select ?v_0 ?J_29) ?I_28))))))
45 | (assert (forall ((?I_33 Int) (?J_34 Int) (?A_35 (Array Int (Array Int Real))) (?B_36 (Array Int (Array Int Real))) (?N_37 Int)) (let ((?v_0 (tptp_msub ?A_35 ?B_36))) (=> (and (and (and (and (and (>= ?I_33 0) (<= ?I_33 ?N_37)) (>= ?J_34 0)) (<= ?J_34 ?N_37)) (= (select (select ?A_35 ?I_33) ?J_34) (select (select ?A_35 ?J_34) ?I_33))) (= (select (select ?B_36 ?I_33) ?J_34) (select (select ?B_36 ?J_34) ?I_33))) (= (select (select ?v_0 ?I_33) ?J_34) (select (select ?v_0 ?J_34) ?I_33))))))
46 | (assert (forall ((?I_38 Int) (?J_39 Int) (?A_40 (Array Int (Array Int Real))) (?N_41 Int)) (let ((?v_0 (trans ?A_40))) (=> (and (and (and (and (>= ?I_38 0) (<= ?I_38 ?N_41)) (>= ?J_39 0)) (<= ?J_39 ?N_41)) (= (select (select ?A_40 ?I_38) ?J_39) (select (select ?A_40 ?J_39) ?I_38))) (= (select (select ?v_0 ?I_38) ?J_39) (select (select ?v_0 ?J_39) ?I_38))))))
47 | (assert (forall ((?I_42 Int) (?J_43 Int) (?A_44 (Array Int (Array Int Real))) (?N_45 Int)) (let ((?v_0 (inv ?A_44))) (=> (and (and (and (and (>= ?I_42 0) (<= ?I_42 ?N_45)) (>= ?J_43 0)) (<= ?J_43 ?N_45)) (= (select (select ?A_44 ?I_42) ?J_43) (select (select ?A_44 ?J_43) ?I_42))) (= (select (select ?v_0 ?I_42) ?J_43) (select (select ?v_0 ?J_43) ?I_42))))))
48 | (assert (forall ((?I0_46 Int) (?J0_47 Int) (?I_48 Int) (?J_49 Int) (?A_50 (Array Int (Array Int Real))) (?B_51 (Array Int (Array Int Real))) (?C_52 (Array Int (Array Int Real))) (?D_53 (Array Int (Array Int Real))) (?E_54 (Array Int (Array Int Real))) (?F_55 (Array Int (Array Int Real))) (?N_56 Int) (?M_57 Int)) (let ((?v_0 (tptp_madd ?A_50 (tptp_mmul ?B_51 (tptp_mmul (tptp_madd (tptp_mmul ?C_52 (tptp_mmul ?D_53 (trans ?C_52))) (tptp_mmul ?E_54 (tptp_mmul ?F_55 (trans ?E_54)))) (trans ?B_51)))))) (=> (and (and (and (and (and (and (and (and (and (and (>= ?I0_46 0) (<= ?I0_46 ?N_56)) (>= ?J0_47 0)) (<= ?J0_47 ?N_56)) (>= ?I_48 0)) (<= ?I_48 ?M_57)) (>= ?J_49 0)) (<= ?J_49 ?M_57)) (= (select (select ?D_53 ?I_48) ?J_49) (select (select ?D_53 ?J_49) ?I_48))) (= (select (select ?A_50 ?I0_46) ?J0_47) (select (select ?A_50 ?J0_47) ?I0_46))) (= (select (select ?F_55 ?I0_46) ?J0_47) (select (select ?F_55 ?J0_47) ?I0_46))) (= (select (select ?v_0 ?I0_46) ?J0_47) (select (select ?v_0 ?J0_47) ?I0_46))))))
49 | (assert (forall ((?Body_58 Real)) (= (sum 0 (- 1) ?Body_58) 0.0)))
50 | (assert (not (= def use)))
51 | (assert (not (=> (and (forall ((?A_59 Int) (?B_60 Int)) (=> (and (and (and (>= ?A_59 0) (>= ?B_60 0)) (<= ?A_59 5)) (<= ?B_60 5)) (= (select (select q_ds1_filter ?A_59) ?B_60) (select (select q_ds1_filter ?B_60) ?A_59)))) (forall ((?C_61 Int) (?D_62 Int)) (=> (and (and (and (>= ?C_61 0) (>= ?D_62 0)) (<= ?C_61 2)) (<= ?D_62 2)) (= (select (select r_ds1_filter ?C_61) ?D_62) (select (select r_ds1_filter ?D_62) ?C_61))))) (forall ((?E_63 Int) (?F_64 Int)) (let ((?v_0 (= 5 ?F_64)) (?v_1 (= 5 ?E_63))) (=> (and (and (and (>= ?E_63 0) (>= ?F_64 0)) (<= ?E_63 5)) (<= ?F_64 5)) (=> (and (and (and (and (and (not (and (= 3 ?E_63) ?v_0)) (not (and (= 4 ?E_63) ?v_0))) (not (and ?v_1 ?v_0))) (= 2 ?E_63)) ?v_1) ?v_0) (= (select xinit_noise 5) 0.0))))))))
52 | (check-sat)
53 | (exit)
54 |
--------------------------------------------------------------------------------
/src/it/resources/regression/smtlib/solving/cvc4/define_fun2.smt2:
--------------------------------------------------------------------------------
1 | (set-option :print-success true)
2 | (set-logic QF_UF)
3 | (declare-sort U 0)
4 | (declare-fun x0 () U)
5 | (declare-fun y0 () U)
6 | (define-fun-rec x1 ((z U)) U z)
7 | (define-fun-rec y1 ((z U)) U z)
8 | (exit)
9 |
--------------------------------------------------------------------------------
/src/it/resources/regression/smtlib/solving/cvc4/define_fun2.smt2.want:
--------------------------------------------------------------------------------
1 | success
2 | success
3 | success
4 | success
5 | success
6 | success
7 | success
8 | success
9 |
--------------------------------------------------------------------------------
/src/it/resources/regression/smtlib/solving/cvc4/define_fun3.smt2:
--------------------------------------------------------------------------------
1 | (set-option :print-success true)
2 | (set-logic QF_UF)
3 | (declare-sort U 0)
4 | (declare-fun x0 () U)
5 | (declare-fun y0 () U)
6 | (define-funs-rec ((x1 ((z U)) U)) (z))
7 | (exit)
8 |
--------------------------------------------------------------------------------
/src/it/resources/regression/smtlib/solving/cvc4/define_fun3.smt2.want:
--------------------------------------------------------------------------------
1 | success
2 | success
3 | success
4 | success
5 | success
6 | success
7 | success
8 |
--------------------------------------------------------------------------------
/src/it/scala/smtlib/it/ProcessInterpreterTests.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package it
3 |
4 | import scala.sys.process._
5 |
6 | import org.scalatest.funsuite.AnyFunSuite
7 |
8 | import java.io.File
9 | import java.io.FileReader
10 |
11 | import parser.Parser
12 | import lexer.Lexer
13 | import printer.RecursivePrinter
14 | import interpreters._
15 |
16 |
17 | class ProcessInterpreterTests extends AnyFunSuite with TestHelpers {
18 |
19 | //TODO: properly get all interpreters
20 | def interpreters: Seq[Interpreter] = Seq(getZ3Interpreter)
21 |
22 | test("Interrupt after free does not throw an exception") {
23 | //TODO: check against all interpreters
24 | val z3Interpreter = getZ3Interpreter
25 |
26 | z3Interpreter.eval(trees.Commands.SetLogic(trees.Commands.AUFLIA()))
27 | z3Interpreter.eval(trees.Commands.CheckSat())
28 | z3Interpreter.free()
29 | z3Interpreter.interrupt()
30 | }
31 |
32 | test("Interrupt can be called multiple times safely") {
33 | //TODO: check against all interpreters
34 | val z3Interpreter = getZ3Interpreter
35 |
36 | z3Interpreter.eval(trees.Commands.SetLogic(trees.Commands.AUFLIA()))
37 | z3Interpreter.eval(trees.Commands.CheckSat())
38 | z3Interpreter.interrupt()
39 | z3Interpreter.interrupt()
40 | z3Interpreter.interrupt()
41 | z3Interpreter.interrupt()
42 | z3Interpreter.interrupt()
43 | }
44 |
45 |
46 | //TODO: test interrupt on a long running check-sat command with big benchmarks
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/it/scala/smtlib/it/SmtLibRunnerTests.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package it
3 |
4 | import scala.sys.process._
5 |
6 | import org.scalatest.funsuite.AnyFunSuite
7 |
8 | import java.io.File
9 | import java.io.FileReader
10 |
11 | import parser.Parser
12 | import lexer.Lexer
13 | import printer.RecursivePrinter
14 | import interpreters._
15 |
16 |
17 | /** Checks the parser on .smt2 files.
18 | *
19 | * Compare the result of running command by command with an interpreter against
20 | * running the corresponding executable directly on the .smt2 files.
21 | *
22 | * TODO: proper way to display warning when not all tests are run because of not found executables.
23 | */
24 | class SmtLibRunnerTests extends AnyFunSuite with TestHelpers {
25 |
26 | filesInResourceDir("regression/smtlib/solving/all", _.endsWith(".smt2")).foreach(file => {
27 | if(isZ3Available) {
28 | test("With Z3: SMTLIB benchmark: " + file.getPath) {
29 | compareWithInterpreter(executeZ3)(getZ3Interpreter, file)
30 | }
31 | }
32 | if(isCVC4Available) {
33 | test("With CVC4: SMTLIB benchmark: " + file.getPath) {
34 | compareWithInterpreter(executeCVC4)(getCVC4Interpreter, file)
35 | }
36 | }
37 | })
38 |
39 | if(isZ3Available) {
40 | filesInResourceDir("regression/smtlib/solving/z3", _.endsWith(".smt2")).foreach(file => {
41 | test("With Z3: SMTLIB benchmark: " + file.getPath) {
42 | compareWithInterpreter(executeZ3)(getZ3Interpreter, file)
43 | }
44 | })
45 | }
46 |
47 | if(isCVC4Available) {
48 | filesInResourceDir("regression/smtlib/solving/cvc4", _.endsWith(".smt2")).foreach(file => {
49 | test("With CVC4: SMTLIB benchmark: " + file.getPath) {
50 | compareWithWant(getCVC4Interpreter, file, new File(file.getPath + ".want"))
51 | }
52 | })
53 | }
54 |
55 |
56 | def compareWithInterpreter(executable: (File) => (String => Unit) => Unit)
57 | (interpreter: Interpreter, file: File) = {
58 | val lexer = new Lexer(new FileReader(file))
59 | val parser = new Parser(lexer)
60 |
61 | executable(file) { (expected: String) =>
62 | val cmd = parser.parseCommand
63 | assert(cmd !== null)
64 | val res: String = interpreter.eval(cmd).toString
65 | assert(expected.trim === res.trim)
66 | }
67 | assert(parser.parseCommand === null)
68 | }
69 |
70 | def compareWithWant(interpreter: Interpreter, file: File, want: File) = {
71 |
72 | val lexer = new Lexer(new FileReader(file))
73 | val parser = new Parser(lexer)
74 |
75 | for(expected <- scala.io.Source.fromFile(want).getLines()) {
76 | val cmd = parser.parseCommand
77 | assert(cmd !== null)
78 | val res: String = interpreter.eval(cmd).toString
79 | assert(expected.trim === res.trim)
80 | }
81 | assert(parser.parseCommand === null)
82 | intercept[smtlib.parser.Parser.UnexpectedEOFException] {
83 | // There shouldn't be anything left on the interpreter parser (the solver process).
84 | interpreter.parser.parseSExpr
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/it/scala/smtlib/it/TestHelpers.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package it
3 |
4 | import scala.sys.process._
5 |
6 | import org.scalatest.FunSuite
7 |
8 | import java.io.File
9 | import java.io.FileReader
10 |
11 | import parser.Parser
12 | import lexer.Lexer
13 | import printer.RecursivePrinter
14 | import interpreters._
15 |
16 | /** Provide helper functions to test solver interfaces and files.
17 | *
18 | * Provides functions to access a list of files in resources.
19 | * Provides functions to get access to an interpreter to
20 | * an SMT solver running locally. Assume standard names of executable
21 | * are available in current working directory.
22 | */
23 | trait TestHelpers {
24 |
25 | private val all: String => Boolean = (s: String) => true
26 | private val resourceDirHard = "src/it/resources/"
27 |
28 | def filesInResourceDir(dir : String, filter : String=>Boolean = all) : Iterable[File] = {
29 | import scala.jdk.CollectionConverters._
30 | val d = this.getClass.getClassLoader.getResource(dir)
31 |
32 | val asFile = if(d == null || d.getProtocol != "file") {
33 | // We are in Eclipse. The only way we are saved is by hard-coding the path
34 | new File(resourceDirHard + dir)
35 | } else new File(d.toURI())
36 |
37 | val files = asFile.listFiles()
38 | if(files == null)
39 | Nil
40 | else
41 | files.filter(f => filter(f.getPath()))
42 | }
43 |
44 | def getZ3Interpreter: Interpreter = Z3Interpreter.buildDefault
45 | def getCVC4Interpreter: Interpreter = CVC4Interpreter.buildDefault
46 |
47 | def isZ3Available: Boolean = try {
48 | val output: String = "z3 -help".!!
49 | true
50 | } catch {
51 | case (_: Exception) => false
52 | }
53 |
54 | def isCVC4Available: Boolean = try {
55 | val output: String = "cvc4".!!
56 | true
57 | } catch {
58 | case (e: Exception) => {
59 | false
60 | }
61 | }
62 |
63 | def executeZ3(file: File)(f: (String) => Unit): Unit = {
64 | Seq("z3", "-smt2", file.getPath) ! ProcessLogger(f, s => ())
65 | }
66 |
67 | def executeCVC4(file: File)(f: (String) => Unit): Unit = {
68 | Seq("cvc4", "--lang", "smt", file.getPath) ! ProcessLogger(f, s => ())
69 | }
70 |
71 | }
72 |
73 |
--------------------------------------------------------------------------------
/src/it/scala/smtlib/it/TheoriesBuilderTests.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package it
3 |
4 | import scala.sys.process._
5 |
6 | import org.scalatest.funsuite.AnyFunSuite
7 |
8 | import java.io.File
9 | import java.io.FileReader
10 |
11 | import interpreters._
12 |
13 | import trees.Terms._
14 | import trees.Commands._
15 | import trees.CommandsResponses._
16 |
17 |
18 | /** Checks that formula build with theories module are correctly handled by solvers */
19 | class TheoriesBuilderTests extends AnyFunSuite with TestHelpers {
20 |
21 |
22 | def mkTest(formula: Term, expectedStatus: Status, prefix: String) = {
23 |
24 | if(isZ3Available) {
25 | test(prefix + ": with Z3") {
26 | val z3Interpreter = getZ3Interpreter
27 | val assertion = Assert(formula)
28 | assert(z3Interpreter.eval(assertion) === Success)
29 | val res = z3Interpreter.eval(CheckSat())
30 | res match {
31 | case CheckSatStatus(status) => assert(status === expectedStatus)
32 | case res => assert(false, "expected a check sat status, but got: " + res)
33 | }
34 | }
35 | }
36 |
37 | if(isCVC4Available) {
38 | test(prefix + ": with CVC4") {
39 | val cvc4Interpreter = getCVC4Interpreter
40 | val assertion = Assert(formula)
41 | assert(cvc4Interpreter.eval(assertion) === Success)
42 | val res = cvc4Interpreter.eval(CheckSat())
43 | res match {
44 | case CheckSatStatus(status) => assert(status === expectedStatus)
45 | case res => assert(false, "expected a check sat status, but got: " + res)
46 | }
47 | }
48 | }
49 |
50 | }
51 |
52 |
53 | {
54 | import theories.Ints._
55 | val theoryString = "Theory of Ints"
56 | var counter = 0
57 | def uniqueName(): String = {
58 | counter += 1
59 | "%d - %s".format(counter, theoryString)
60 | }
61 |
62 |
63 | val f1 = GreaterEquals(NumeralLit(42), NumeralLit(12))
64 | mkTest(f1, SatStatus, uniqueName())
65 |
66 | val f2 = GreaterEquals(NumeralLit(42), NumeralLit(52))
67 | mkTest(f2, UnsatStatus, uniqueName())
68 |
69 | //divisible not supported by z3
70 | //val f3 = Divisible(2, NumeralLit(16))
71 | //mkTest(f3, SatStatus, uniqueName())
72 |
73 | val f4 = LessThan(NumeralLit(5), NumeralLit(10))
74 | mkTest(f4, SatStatus, uniqueName())
75 |
76 | val f5 = LessThan(Add(NumeralLit(6), NumeralLit(5)), NumeralLit(10))
77 | mkTest(f5, UnsatStatus, uniqueName())
78 |
79 | val f6 = LessThan(Neg(NumeralLit(5)), NumeralLit(2))
80 | mkTest(f6, SatStatus, uniqueName())
81 |
82 | val f7 = LessEquals(Sub(NumeralLit(5), NumeralLit(3)), NumeralLit(2))
83 | mkTest(f7, SatStatus, uniqueName())
84 |
85 | val f8 = LessEquals(Sub(NumeralLit(5), NumeralLit(3)), NumeralLit(1))
86 | mkTest(f8, UnsatStatus, uniqueName())
87 | }
88 |
89 | {
90 | import theories.Reals._
91 | val theoryString = "Theory of Reals"
92 | var counter = 0
93 | def uniqueName(): String = {
94 | counter += 1
95 | "%d - %s".format(counter, theoryString)
96 | }
97 |
98 |
99 | val f1 = GreaterEquals(NumeralLit(42), NumeralLit(12))
100 | mkTest(f1, SatStatus, uniqueName())
101 |
102 | val f2 = GreaterEquals(NumeralLit(42), NumeralLit(52))
103 | mkTest(f2, UnsatStatus, uniqueName())
104 |
105 | val f4 = LessThan(NumeralLit(5), NumeralLit(10))
106 | mkTest(f4, SatStatus, uniqueName())
107 |
108 | val f5 = LessThan(Add(NumeralLit(6), NumeralLit(5)), NumeralLit(10))
109 | mkTest(f5, UnsatStatus, uniqueName())
110 |
111 | val f6 = LessThan(Neg(NumeralLit(5)), NumeralLit(2))
112 | mkTest(f6, SatStatus, uniqueName())
113 |
114 | val f7 = LessEquals(Sub(NumeralLit(5), NumeralLit(3)), NumeralLit(2))
115 | mkTest(f7, SatStatus, uniqueName())
116 |
117 | val f8 = LessEquals(Sub(NumeralLit(5), NumeralLit(3)), NumeralLit(1))
118 | mkTest(f8, UnsatStatus, uniqueName())
119 | }
120 |
121 | {
122 | import theories.FixedSizeBitVectors._
123 | val theoryString = "Theory of Bit Vectors"
124 | var counter = 0
125 | def uniqueName(): String = {
126 | counter += 1
127 | "%d - %s".format(counter, theoryString)
128 | }
129 |
130 |
131 | val f1 = SGreaterEquals(BitVectorConstant(42, 32), BitVectorConstant(12, 32))
132 | mkTest(f1, SatStatus, uniqueName())
133 |
134 | val f2 = SGreaterEquals(BitVectorConstant(42, 32), BitVectorConstant(52, 32))
135 | mkTest(f2, UnsatStatus, uniqueName())
136 |
137 | val f3 = SGreaterEquals(BitVectorLit(List(false, true, false)), BitVectorLit(List(false, false, true)))
138 | mkTest(f3, SatStatus, uniqueName())
139 |
140 | val f4 = SLessThan(BitVectorConstant(5, 32), BitVectorConstant(10, 32))
141 | mkTest(f4, SatStatus, uniqueName())
142 |
143 | val f5 = SLessThan(Add(BitVectorConstant(6, 32), BitVectorConstant(5, 32)), BitVectorConstant(10, 32))
144 | mkTest(f5, UnsatStatus, uniqueName())
145 |
146 | val f6 = SLessThan(Neg(BitVectorConstant(5, 32)), BitVectorConstant(2, 32))
147 | mkTest(f6, SatStatus, uniqueName())
148 |
149 | val f7 = SLessEquals(Sub(BitVectorConstant(5, 32), BitVectorConstant(3, 32)), BitVectorConstant(2, 32))
150 | mkTest(f7, SatStatus, uniqueName())
151 |
152 | val f8 = SLessEquals(Sub(BitVectorConstant(5, 32), BitVectorConstant(3, 32)), BitVectorConstant(1, 32))
153 | mkTest(f8, UnsatStatus, uniqueName())
154 |
155 | val f9 = UGreaterThan(BitVectorLit(List(true, false)), BitVectorLit(List(false, true)))
156 | mkTest(f9, SatStatus, uniqueName())
157 |
158 | val f10 = UGreaterThan(BitVectorLit(List(true, false)), BitVectorLit(List(true, false)))
159 | mkTest(f10, UnsatStatus, uniqueName())
160 |
161 | val f11 = UGreaterEquals(BitVectorLit(List(true, false)), BitVectorLit(List(true, false)))
162 | mkTest(f11, SatStatus, uniqueName())
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/Interpreter.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 |
3 | import parser.Parser
4 | import trees.Commands.{Script, Command}
5 | import trees.CommandsResponses.CommandResponse
6 | import trees.Terms._
7 | import printer.Printer
8 |
9 | /*
10 | * An interpreter is a stateful object that can eval Commands and returns
11 | * CommandResponse.
12 | *
13 | * Note that despite returning the command response, the interpreter should handle the printing
14 | * of those responses itself. That is because it needs to handle the verbosity and *-output-channel
15 | * options commands, and will do the correct printing depending on the internal state.
16 | * The responses are returned as a way to progamatically communicate with a solver.
17 |
18 | * TODO: The interaction of the set-option for the channels with the eval interface
19 | seems just wrong. Need to clarify that.
20 | */
21 | trait Interpreter {
22 |
23 | val printer: Printer
24 | val parser: Parser
25 |
26 | def eval(cmd: SExpr): SExpr
27 |
28 | //A free method is kind of justified by the need for the IO streams to be closed, and
29 | //there seems to be a decent case in general to have such a method for things like solvers
30 | //note that free can be used even if the solver is currently solving, and act as a sort of interrupt
31 | def free(): Unit
32 |
33 | def interrupt(): Unit
34 | }
35 |
36 | object Interpreter {
37 |
38 | import java.io.Reader
39 | import java.io.FileReader
40 | import java.io.BufferedReader
41 | import java.io.File
42 |
43 | def execute(script: Script)(implicit interpreter: Interpreter): Unit = {
44 | for(cmd <- script.commands)
45 | interpreter.eval(cmd)
46 | }
47 |
48 | def execute(scriptReader: Reader)(implicit interpreter: Interpreter): Unit = {
49 | val parser = new Parser(new lexer.Lexer(scriptReader))
50 | val cmd: Command = null
51 | do {
52 | val cmd = parser.parseCommand
53 | if(cmd != null)
54 | interpreter.eval(cmd)
55 | } while(cmd != null)
56 | }
57 |
58 | def execute(file: File)(implicit interpreter: Interpreter): Unit = {
59 | val parser = new Parser(new lexer.Lexer(new BufferedReader(new FileReader(file))))
60 | var cmd: Command = null
61 | do {
62 | cmd = parser.parseCommand
63 | if(cmd != null)
64 | interpreter.eval(cmd)
65 | } while(cmd != null)
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/common/Binary.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package common
3 |
4 | import scala.language.implicitConversions
5 |
6 | class Binary private(val digits: List[Boolean]) {
7 |
8 | /*
9 | * TODO: a dimension/size concept
10 | */
11 |
12 | //take the 32 least significant bits
13 | def toIntBits: Int = {
14 | ((toLongBits << 32) >>> 32).toInt
15 | }
16 |
17 | def toLongBits: Long = {
18 | val allReversedBits: List[Boolean] = digits.take(64).reverse.padTo(64, false)
19 | allReversedBits.foldRight(0L)((bit, bits) => ((bits<<1) | (if(bit) 1 else 0)))
20 | }
21 |
22 | //transform to a 32 bits integer, respecting 2 complements
23 | def toInt: Int = {
24 | val allReversedBits: List[Boolean] = digits.take(32).reverse.padTo(32, digits.head)
25 | allReversedBits.foldRight(0)((bit, bits) => ((bits<<1) | (if(bit) 1 else 0)))
26 | }
27 |
28 |
29 | /*
30 | * TODO: define how the size is affected
31 | */
32 | def &(that: Binary): Binary = Binary(this.digits.zip(that.digits).map(p => p._1 && p._2))
33 | def |(that: Binary): Binary = {
34 | val (padThis, padThat) =
35 | if(this.digits.size < that.digits.size)
36 | (this.digits.padTo(that.digits.size, false), that.digits)
37 | else
38 | (this.digits, that.digits.padTo(this.digits.size, false))
39 | Binary(padThis.zip(padThat).map(p => p._1 || p._2))
40 | }
41 |
42 | def ^(that: Binary): Binary = ???
43 | def >>(that: Binary): Binary = ???
44 | def >>>(that: Binary): Binary = ???
45 | def <<(that: Binary): Binary = ???
46 |
47 | def unary_~ : Binary = ???
48 |
49 | }
50 |
51 | object Binary {
52 |
53 | def apply(digits: List[Boolean]) = new Binary(digits)
54 |
55 | def apply(hexa: Hexadecimal) = new Binary(hexa.toBinary)
56 |
57 | implicit def int2binary(bitVector: Int): Binary = ???
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/common/Hexadecimal.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package common
3 |
4 |
5 | /** Hexadecimal number value
6 | *
7 | * This provides a type safe way to manipulate hexadecimal number.
8 | * The main constructor is private, but the companion object provides
9 | * a number of way to produce an Hexadecimal representation, from a
10 | * string or from any integer type.
11 | *
12 | * An hexadecimal number value really depends on the context in which
13 | * it is considered. It can always be interpreted as an unsigned, infinite
14 | * precision integer, or as a negative number in two-complement. A value
15 | * like 'F' could either be 16 or -1, depending if it is interpreted as an
16 | * unsigned value on an integral type of more than 4 bits, or if it is sign
17 | * extended in the corresponding integral representation. You should consider
18 | * the Hexadecimal as a concise syntax to represent a sequence of bytes, with
19 | * convenient methods to convert to and from integers, and not as an actual
20 | * number.
21 | */
22 | class Hexadecimal private(
23 | /** The string representation, using upper cases */
24 | val repr: String
25 | ) {
26 | //should be normalized to upper cases
27 | require(repr.forall(c =>
28 | (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')
29 | ))
30 |
31 | /** extract the Int represented by this hexadecimal
32 | *
33 | * Returns the Int value represented by this hexadecimal number.
34 | * Assumes the hexadecimal represents 32 bits, by padding 0 in
35 | * front if necessary, and by ignoring extra digits.
36 | *
37 | * It returns the Int encoded with the exact 32 bits, meaning
38 | * it could return negative number.
39 | */
40 | def toInt: Int = {
41 | val padding = repr.reverse.drop(16)
42 | require(padding.forall(c => c == '0'))
43 |
44 | repr.foldLeft(0)((acc, c) => {
45 | acc*16 + c.asDigit//asDigit works for 'A', 'F', ...
46 | })
47 | }
48 |
49 | def toBinary: List[Boolean] = {
50 | repr.flatMap{
51 | case '0' => List(false, false, false, false)
52 | case '1' => List(false, false, false, true )
53 | case '2' => List(false, false, true , false)
54 | case '3' => List(false, false, true , true )
55 | case '4' => List(false, true , false, false)
56 | case '5' => List(false, true , false, true )
57 | case '6' => List(false, true , true , false)
58 | case '7' => List(false, true , true , true )
59 | case '8' => List(true , false, false, false)
60 | case '9' => List(true , false, false, true )
61 | case 'A' => List(true , false, true , false)
62 | case 'B' => List(true , false, true , true )
63 | case 'C' => List(true , true , false, false)
64 | case 'D' => List(true , true , false, true )
65 | case 'E' => List(true , true , true , false)
66 | case 'F' => List(true , true , true , true )
67 | }.toList
68 | }
69 |
70 | override def toString: String = "#x" + repr
71 |
72 | override def equals(that: Any): Boolean = (that != null) && (that match {
73 | case (h: Hexadecimal) => repr == h.repr
74 | case _ => false
75 | })
76 |
77 | override def hashCode: Int = repr.hashCode
78 |
79 | //TODO: take subpart of hexa (trunc from 32 bits to 8 bits for example)
80 |
81 | }
82 |
83 | object Hexadecimal {
84 |
85 | def fromString(str: String): Option[Hexadecimal] = {
86 | var error = false
87 | val repr = str.map(c => {
88 | if(isDigit(c))
89 | c.toUpper
90 | else {
91 | error = true
92 | c
93 | }
94 | })
95 | if(error) None else Some(new Hexadecimal(repr))
96 | }
97 |
98 | /** return a 32-bits hexadecimal integer */
99 | def fromInt(n: Int): Hexadecimal = {
100 | if(n < 0) {
101 | val res = "00000000".toArray
102 | for(i <- 0 until 8) {
103 | val digit = (n >> (32 - 4*(i+1))) & 15
104 | res(i) = toDigit(digit)
105 | }
106 | fromString(res.mkString).get
107 | } else {
108 |
109 | var i = 0
110 | var rest = n
111 | var repr = ""
112 |
113 | while(i < 8) {
114 | val end = rest & 15
115 | rest = rest >> 4
116 | repr = s"${toDigit(end)}$repr"
117 | i += 1
118 | }
119 |
120 | fromString(repr).get
121 | }
122 | }
123 |
124 | def fromByte(b: Byte): Hexadecimal = fromBigInt(BigInt(b), 2)
125 |
126 | def fromShort(s: Short): Hexadecimal = fromBigInt(BigInt(s), 4)
127 |
128 | def fromLong(l: Long): Hexadecimal = fromBigInt(BigInt(l), 16)
129 |
130 |
131 | /** convert a BigInt to an Hexadecimal
132 | *
133 | * The resulting hexadecimal will always be of size specified
134 | * by digits. The conversion always truncates the theoretical
135 | * representation, which could have the effect of changing
136 | * a positive integer into a negative value.
137 | *
138 | * Negative numbers are converted by taking the theoretical
139 | * two complement representation, with an infinite number of
140 | * 1s in front, and then we simply truncate for the correct length.
141 | * It has the effect that it could change a negative number into
142 | * a positive number in the corresponding length.
143 | */
144 | def fromBigInt(bi: BigInt, digits: Int): Hexadecimal = {
145 | val isPositive = bi >= 0
146 | val absolute = bi.abs
147 | val absoluteRepr: String = absolute.toString(16)
148 |
149 | if(isPositive) {
150 | fromString(absoluteRepr.reverse.take(digits).padTo(digits, '0').reverse).get
151 | } else {
152 |
153 | val bytes: Array[Byte] = bi.toByteArray
154 | val fullHexa: String = bytes.map(b => byteToHexString(b)).mkString
155 |
156 | fromString(fullHexa.reverse.take(digits).padTo(digits, 'F').reverse).get
157 | }
158 |
159 | }
160 |
161 | def toDigit(n: Int): Char = {
162 | require(n >= 0 && n < 16)
163 | if(n >= 0 && n < 10) (n + '0').toChar else ('A' + (n - 10)).toChar
164 | }
165 |
166 | /** convert a digit byte to corresponding char
167 | *
168 | * Only works for bytes between 0 and 16
169 | */
170 | def toDigit(n: Byte): Char = {
171 | require(n >= 0 && n < 16)
172 | if(n >= 0 && n < 10) (n + '0').toChar else ('A' + (n - 10)).toChar
173 | }
174 |
175 |
176 | def isDigit(c: Char): Boolean =
177 | c.isDigit || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')
178 |
179 | /* generate a two-digit (0-f) hex string for the given byte. */
180 | private def byteToHexString(b: Byte): String = {
181 | val h = Integer.toHexString(b)
182 | if (b >= 0) {
183 | val missing = 2 - h.length
184 | ("0" * missing) + h
185 | } else {
186 | val extra = h.length - 2
187 | h.drop(extra)
188 | }
189 | }
190 |
191 | }
192 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/common/LinkedList.scala:
--------------------------------------------------------------------------------
1 | package smtlib.common
2 |
3 | /*
4 | * Mutable data structure with O(1) append and prepend as
5 | * well as pop operation.
6 | */
7 | class LinkedList[T] {
8 |
9 | private class Node(val el: T, var next: Node)
10 |
11 | private var _head: Node = null
12 | private var _last: Node = null
13 |
14 | def append(el: T): Unit = {
15 | if(_head == null) {
16 | _head = new Node(el, null)
17 | _last = _head
18 | } else {
19 | val previousLast = _last
20 | _last = new Node(el, null)
21 | previousLast.next = _last
22 | }
23 | }
24 |
25 | def prepend(el: T): Unit = {
26 | if(_head == null) {
27 | _head = new Node(el, null)
28 | _last = _head
29 | } else {
30 | _head = new Node(el, _head)
31 | }
32 | }
33 |
34 | def pop(): T = {
35 | val firstElem = _head.el
36 | if(_head.next == null) {
37 | _head = null
38 | _last = null
39 | } else {
40 | _head = _head.next
41 | }
42 | firstElem
43 | }
44 |
45 | def size: Int = {
46 | var res = 0
47 | var headPtr = _head
48 | while(headPtr != null) {
49 | res += 1
50 | headPtr = headPtr.next
51 | }
52 | res
53 | }
54 |
55 | def isEmpty: Boolean = _head == null
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/common/Positions.scala:
--------------------------------------------------------------------------------
1 | package smtlib.common
2 |
3 | case class Position(line: Int, col: Int) extends Ordered[Position] {
4 |
5 | def compare(that: Position) = {
6 | val ld = this.line - that.line
7 | if (ld == 0) {
8 | this.col - that.col
9 | } else {
10 | ld
11 | }
12 | }
13 |
14 | override def toString: String = s"($line, $col)"
15 |
16 | }
17 |
18 |
19 | /** Adds a position attribute to objects
20 | *
21 | * The position is optional, first because of the nature of trait
22 | * it is cumbersome to force a position at instantiation time. But
23 | * mainly because we don't want to always force a Term or Command
24 | * to have a position. Typically, if the Command is generated from a
25 | * program, its position should be None. All terms parsed from some
26 | * input should have a position relative to the input.
27 | *
28 | * Position is always a single line+col, which should generally be
29 | * interpreted as the position of the first character corresponding
30 | * to the token/object. We might want to consider a solution for describing
31 | * starting+ending position
32 | */
33 | trait Positioned {
34 |
35 | private[this] var _pos: Option[Position] = None
36 |
37 | def setPos(pos: Position): this.type = {
38 | _pos = Some(pos)
39 | this
40 | }
41 |
42 | def setPos(that: Positioned): this.type = {
43 | _pos = that.optPos
44 | this
45 | }
46 |
47 | def getPos: Position = {
48 | _pos.get
49 | }
50 |
51 | def optPos: Option[Position] = _pos
52 |
53 | def hasPos: Boolean = _pos.nonEmpty
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/drivers/Main.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package drivers
3 |
4 | import java.io.FileReader
5 |
6 | import interpreters._
7 | import lexer._
8 | import parser._
9 | import trees._
10 |
11 | /** Provides an entry point to run a command line wrapper on a driver */
12 | object Main {
13 |
14 |
15 | def main(args: Array[String]): Unit = {
16 |
17 | /*
18 | * first argument must be solver. Probably we should support notion of
19 | * version as well.
20 | */
21 | val solver = args(0)
22 |
23 | if(solver == "cvc4") {
24 |
25 | val cvc4Interpreter = CVC4Interpreter.buildDefault
26 | val l = new Lexer(new FileReader(args(1)))
27 | val p = new Parser(l)
28 |
29 | var cmd = p.parseCommand
30 | while(cmd != null) {
31 | println(cvc4Interpreter.eval(cmd))
32 | cmd = p.parseCommand
33 | }
34 | }
35 |
36 | }
37 |
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/drivers/SemanticsDriver.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package drivers
3 |
4 | import trees.Terms._
5 | import trees.Commands._
6 | import trees.CommandsResponses._
7 | import printer.RecursivePrinter
8 |
9 |
10 | /** Provide standard complient behaviour for a sequence of commands.
11 | *
12 | * This driver will properly understand the whole SMT-LIB 2.5 language,
13 | * maintaining proper state and forwarding work to an underlying solver.
14 | * The behaviour of this driver is to perfectly follow the standard, and
15 | * properly abstract the peculiarities of the black box solvers so that
16 | * they can be used with SMT-LIB 2.5 language.
17 | *
18 | * One difficult in implementing the SMT-LIB standard is that the standard
19 | * is designed for process interaction, relying on both a standard output and
20 | * standard error channel. Standard output and error are part of the interface
21 | * of the driver, and by default will be available on the driver. If one sets
22 | * the :diagnostic-output-channel or :regular-output-channel options, that
23 | * will redirect this behaviour and send the outputs to files.
24 | * Basically: stdout and stderr are the iterator attached to this driver.
25 | *
26 | * TODO: this is work in progress, not usable yet.
27 | */
28 | class SemanticsDriver(
29 | rawSolver: Interpreter,
30 | onRegularOutput: (CommandResponse) => Unit,
31 | onDiagnosticOutput: (String) => Unit
32 | ) {
33 |
34 | import SemanticsDriver._
35 |
36 | private var regularOutputChannel: (CommandResponse) => Unit = onRegularOutput
37 | private var diagnosticOutputChannel: (String) => Unit = onDiagnosticOutput
38 |
39 | private def fileRegularOutputChannel(name: String): (CommandResponse) => Unit = {
40 | val f = new java.io.FileWriter(name)
41 | (res: CommandResponse) => {
42 | f.write(RecursivePrinter.toString(res))
43 | f.write("\n")
44 | }
45 | }
46 | private def fileDiagnosticOutputChannel(name: String): (String) => Unit = {
47 | val f = new java.io.FileWriter(name)
48 | (info: String) => {
49 | f.write(info)
50 | f.write("\n")
51 | }
52 | }
53 |
54 | private var executionMode: ExecutionMode = StartMode
55 |
56 | private var logic: Option[Logic] = None
57 | private var printSuccess = true
58 | private var globalDeclarations = false
59 | private var produceModels = false
60 |
61 | private def doPrintSuccess(): Unit = {
62 | if(printSuccess)
63 | onRegularOutput(Success)
64 | }
65 |
66 | protected def processSetOption(option: SMTOption): Unit = option match {
67 |
68 | case DiagnosticOutputChannel(value) =>
69 | //TODO: can we set stdout for diagnostic output channel and redirect it to regular ?
70 | if(value == "stderr")
71 | diagnosticOutputChannel = onDiagnosticOutput
72 | else
73 | diagnosticOutputChannel = fileDiagnosticOutputChannel(value)
74 | doPrintSuccess()
75 |
76 |
77 | case GlobalDeclarations(value) =>
78 | if(executionMode != StartMode) {
79 | regularOutputChannel(Error("global-declaration can only be set in Start mode"))
80 | } else {
81 | globalDeclarations = value
82 | rawSolver.eval(SetOption(option))
83 | doPrintSuccess()
84 | }
85 |
86 | case InteractiveMode(value) =>
87 | regularOutputChannel(Unsupported)
88 |
89 | case PrintSuccess(value) =>
90 | printSuccess = value
91 | doPrintSuccess()
92 |
93 | case ProduceAssertions(value) =>
94 | regularOutputChannel(Unsupported)
95 |
96 | case ProduceAssignments(value) =>
97 | regularOutputChannel(Unsupported)
98 |
99 | case ProduceModels(value) =>
100 | if(executionMode != StartMode) {
101 | regularOutputChannel(Error("produce-models can only be set in Start mode"))
102 | } else {
103 | produceModels = value
104 | rawSolver.eval(SetOption(option))
105 | doPrintSuccess()
106 | }
107 |
108 | case ProduceProofs(value) =>
109 | regularOutputChannel(Unsupported)
110 |
111 | case ProduceUnsatAssumptions(value) =>
112 | regularOutputChannel(Unsupported)
113 |
114 | case ProduceUnsatCores(value) =>
115 | regularOutputChannel(Unsupported)
116 |
117 | case RandomSeed(value) =>
118 | regularOutputChannel(Unsupported)
119 |
120 | case RegularOutputChannel(value) =>
121 | if(value == "stdout")
122 | regularOutputChannel = onRegularOutput
123 | else
124 | regularOutputChannel = fileRegularOutputChannel(value)
125 | doPrintSuccess()
126 |
127 | case ReproducibleResourceLimit(value) =>
128 | regularOutputChannel(Unsupported)
129 |
130 | case Verbosity(value) =>
131 | regularOutputChannel(Unsupported)
132 |
133 | case AttributeOption(attribute) =>
134 | regularOutputChannel(Unsupported)
135 |
136 | case _ => ???
137 | }
138 |
139 | protected def processGetInfo(infoFlag: InfoFlag): Unit = infoFlag match {
140 | case AllStatisticsInfoFlag() =>
141 | regularOutputChannel(Unsupported)
142 | case AssertionStackLevelsInfoFlag() =>
143 | regularOutputChannel(Unsupported)
144 | case AuthorsInfoFlag() =>
145 | regularOutputChannel(Unsupported)
146 | case ErrorBehaviorInfoFlag() =>
147 | regularOutputChannel(Unsupported)
148 | case NameInfoFlag() =>
149 | regularOutputChannel(Unsupported)
150 | case ReasonUnknownInfoFlag() =>
151 | regularOutputChannel(Unsupported)
152 | case VersionInfoFlag() =>
153 | regularOutputChannel(Unsupported)
154 | case KeywordInfoFlag(keyword) =>
155 | regularOutputChannel(Unsupported)
156 | }
157 |
158 |
159 | private class AssertionLevel {
160 |
161 | var assertions: Set[Term] = Set()
162 |
163 | private var sortSymbols: Map[SSymbol, Int] = Map()
164 | private var sortAliases: Map[SSymbol, (Seq[SSymbol], Sort)] = Map()
165 |
166 | def isSortDefined(name: SSymbol): Boolean =
167 | sortSymbols.contains(name) || sortAliases.contains(name)
168 |
169 | def newSortSymbol(name: SSymbol, arity: Int): Unit = {
170 | require(!sortSymbols.contains(name))
171 | sortSymbols += (name -> arity)
172 | }
173 | def newSortAlias(name: SSymbol, params: Seq[SSymbol], body: Sort): Unit = {
174 | require(!sortAliases.contains(name))
175 | sortAliases += (name -> ((params, body)))
176 | }
177 |
178 |
179 | var declareFuns: Set[DeclareFun] = Set()
180 | var declareConsts: Set[DeclareConst] = Set()
181 | }
182 |
183 | private var assertionStack: List[AssertionLevel] = List(new AssertionLevel)
184 |
185 | private def firstAssertionLevel: AssertionLevel = assertionStack.last
186 | private def currentAssertionLevel: AssertionLevel = assertionStack.head
187 |
188 | private def processPop(n: Int): Unit = {
189 | if(executionMode == StartMode)
190 | regularOutputChannel(Error("You cannot use pop in Start mode"))
191 | else if(assertionStack.size - n <= 0)
192 | regularOutputChannel(Error("You cannot pop more elements than was pushed"))
193 | else {
194 | assertionStack = assertionStack.drop(n)
195 | executionMode = AssertMode
196 | rawSolver.eval(Pop(n))
197 | doPrintSuccess()
198 | }
199 | }
200 |
201 | private def processPush(n: Int): Unit = {
202 | if(executionMode == StartMode)
203 | regularOutputChannel(Error("You cannot use push in Start mode"))
204 | else {
205 | for(i <- 1 to n)
206 | assertionStack ::= new AssertionLevel
207 | executionMode = AssertMode
208 | rawSolver.eval(Push(n))
209 | doPrintSuccess()
210 | }
211 | }
212 |
213 | /* check that the sort is well defined: correct arity, symbol in context.
214 | * TODO: how to check for built-in sorts?
215 | */
216 | def checkSort(sort: Sort, params: Seq[SSymbol]): Unit = {
217 |
218 | }
219 |
220 |
221 | def eval(command: Command): Unit = {
222 |
223 | if(executionMode == ExitMode) {
224 | regularOutputChannel(Error("The solver has exited."))
225 | } else {
226 |
227 | command match {
228 |
229 | case DeclareSort(name, arity) => {
230 | //TODO: global definitions
231 | if(assertionStack.exists(al => al.isSortDefined(name))) {
232 | regularOutputChannel(Error("Sort " + name + " already defined"))
233 | } else {
234 | currentAssertionLevel.newSortSymbol(name, arity)
235 | executionMode = AssertMode
236 | rawSolver.eval(command)
237 | doPrintSuccess()
238 | }
239 | }
240 |
241 | case DefineSort(name, params, body) => {
242 | //TODO: global definitions
243 | //TODO: check well defined sort
244 | if(assertionStack.exists(al => al.isSortDefined(name))) {
245 | regularOutputChannel(Error("Sort " + name + " already defined"))
246 | } else {
247 | currentAssertionLevel.newSortAlias(name, params, body)
248 | executionMode = AssertMode
249 | rawSolver.eval(command)
250 | doPrintSuccess()
251 | }
252 | }
253 |
254 | case GetInfo(infoFlag) => {
255 | processGetInfo(infoFlag)
256 | }
257 |
258 | case Exit() => {
259 | executionMode = ExitMode
260 | rawSolver.eval(command)
261 | }
262 |
263 | case Pop(n) => {
264 | processPop(n)
265 | }
266 | case Push(n) => {
267 | processPush(n)
268 | }
269 |
270 | case Reset() => {
271 | regularOutputChannel = onRegularOutput
272 | diagnosticOutputChannel = onDiagnosticOutput
273 | printSuccess = true
274 | logic = None
275 | globalDeclarations = false
276 | produceModels = false
277 |
278 | //TODO: if supported, else just emulate by creating a fresh instance
279 | rawSolver.eval(command)
280 | }
281 |
282 | case ResetAssertions() => {
283 | //TODO: what exactly to do with global declarations and declarations at the top level
284 | assertionStack = List(new AssertionLevel)
285 | rawSolver.eval(command)
286 | doPrintSuccess()
287 | }
288 |
289 | case SetLogic(log) => {
290 | if(executionMode != StartMode) {
291 | regularOutputChannel(Error("set-logic is only allowed while in Start mode"))
292 | } else {
293 | rawSolver.eval(command)
294 | logic = Some(log)
295 | executionMode = AssertMode
296 | }
297 | }
298 |
299 | case SetOption(option) => {
300 | processSetOption(option)
301 | }
302 |
303 | case _ => ???
304 | }
305 |
306 | }
307 | }
308 |
309 |
310 | //val regularOutput: Iterator[CommandResponse]
311 |
312 | //val diagnosticOutput: Iterator[String]
313 |
314 | }
315 |
316 | object SemanticsDriver {
317 |
318 | trait ExecutionMode
319 | case object StartMode extends ExecutionMode
320 | case object AssertMode extends ExecutionMode
321 | case object SatMode extends ExecutionMode
322 | case object UnsatMode extends ExecutionMode
323 | case object ExitMode extends ExecutionMode
324 |
325 | }
326 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/drivers/cvc4/SemanticsDecorator.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package drivers
3 | package cvc4
4 |
5 | import trees.Commands._
6 |
7 |
8 | trait SemanticsDecorator extends SemanticsDriver {
9 |
10 |
11 | override def eval(cmd: Command): Unit = {
12 | super.eval(cmd)
13 |
14 | //TODO: add code specific to cvc4 to use the raw solver here
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/drivers/package.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 |
3 | /** provides drivers that adapt standard SMT-LIB to solver specific behaviour
4 | *
5 | * In particula, some solvers only support a subset of SMT-LIB or an outdated
6 | * version. The aim of the drivers are to simplify the interface for other tools.
7 | * All the tools have to be concerned about is to follow the SMT-LIB standard, and
8 | * the driver will take care of any peculiarity of the solver.
9 | */
10 | package object drivers {
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/extensions/tip/Parser.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package extensions.tip
3 |
4 | import smtlib.lexer.{Tokens => LT}
5 | import smtlib.trees.Terms._
6 | import smtlib.trees.Commands._
7 | import smtlib.common.Position
8 |
9 | object Tokens {
10 | import LT.ReservedWord
11 |
12 | case object Lambda extends ReservedWord
13 | case object Match extends ReservedWord
14 | case object Case extends ReservedWord
15 | case object Default extends ReservedWord
16 | case object At extends ReservedWord
17 | case object AssertNot extends ReservedWord
18 | }
19 |
20 | class Lexer(reader: java.io.Reader) extends lexer.Lexer(reader) {
21 | import LT.Token
22 |
23 | override protected def toReserved(s: String): Option[Token] = s match {
24 | case "lambda" => Some(Token(Tokens.Lambda))
25 | case "match" => Some(Token(Tokens.Match))
26 | case "case" => Some(Token(Tokens.Case))
27 | case "default" => Some(Token(Tokens.Default))
28 | case "@" => Some(Token(Tokens.At))
29 | case "assert-not" => Some(Token(Tokens.AssertNot))
30 | case _ => super.toReserved(s)
31 | }
32 | }
33 |
34 | class Parser(lexer: Lexer) extends parser.Parser(lexer) {
35 | import Terms._
36 | import Commands._
37 |
38 | override protected def parseTermWithoutParens(startPos: Position): Term = getPeekToken.kind match {
39 | case Tokens.Lambda =>
40 | eat(Tokens.Lambda)
41 | val args = parseMany(() => parseSortedVar)
42 | val body = parseTerm
43 | Lambda(args, body)
44 |
45 | case Tokens.At =>
46 | eat(Tokens.At)
47 | val (caller +: args) = parseUntil(LT.CParen, eatEnd = false)(() => parseTerm)
48 | Application(caller, args)
49 |
50 | case Tokens.Match =>
51 | eat(Tokens.Match)
52 | val scrut = parseTerm
53 | val cases = parseUntil(LT.CParen, eatEnd = false) { () =>
54 | eat(LT.OParen)
55 | eat(Tokens.Case)
56 | val pattern = getPeekToken.kind match {
57 | case Tokens.Default =>
58 | eat(Tokens.Default)
59 | Default
60 |
61 | case LT.OParen =>
62 | val (sym, binders) = parseOneOrMore(() => parseSymbol)
63 | CaseClass(sym, binders)
64 |
65 | case _ =>
66 | val sym = parseSymbol
67 | CaseObject(sym)
68 | }
69 | val rhs = parseTerm
70 | eat(LT.CParen)
71 | Case(pattern, rhs)
72 | }
73 | Match(scrut, cases)
74 |
75 | case _ => super.parseTermWithoutParens(startPos)
76 | }
77 |
78 | private def parseParTerm: (Option[Seq[SSymbol]], Term) = getPeekToken.kind match {
79 | case LT.OParen =>
80 | val startPos = getPeekToken.getPos
81 | eat(LT.OParen)
82 | getPeekToken.kind match {
83 | case LT.Par =>
84 | eat(LT.Par)
85 | val tps = parseMany(() => parseSymbol)
86 | val res = parseTerm
87 | eat(LT.CParen)
88 | (Some(tps), res)
89 |
90 | case _ =>
91 | val res = parseTermWithoutParens(startPos)
92 | eat(LT.CParen)
93 | (None, res)
94 | }
95 | case _ => (None, parseTerm)
96 | }
97 |
98 | override protected def parseCommandWithoutParens: Command = getPeekToken.kind match {
99 | case Tokens.AssertNot =>
100 | eat(Tokens.AssertNot)
101 | val (optTps, res) = parseParTerm
102 | optTps match {
103 | case Some(tps) => AssertPar(tps, theories.Core.Not(res))
104 | case None => Assert(theories.Core.Not(res))
105 | }
106 |
107 | case LT.Assert =>
108 | eat(LT.Assert)
109 | val (optTps, res) = parseParTerm
110 | optTps match {
111 | case Some(tps) => AssertPar(tps, res)
112 | case None => Assert(res)
113 | }
114 |
115 | case LT.DeclareConst =>
116 | eat(LT.DeclareConst)
117 | def parseDecl: (SSymbol, Sort) = {
118 | val sym = parseSymbol
119 | val sort = parseSort
120 | (sym, sort)
121 | }
122 | getPeekToken.kind match {
123 | case LT.OParen =>
124 | eat(LT.OParen)
125 | eat(LT.Par)
126 | val tps = parseMany(() => parseSymbol)
127 | val (sym, sort) = parseWithin(LT.OParen, LT.CParen)(() => parseDecl)
128 | eat(LT.CParen)
129 | DeclareConstPar(tps, sym, sort)
130 | case _ =>
131 | val (sym, sort) = parseDecl
132 | DeclareConst(sym, sort)
133 | }
134 |
135 | case LT.DeclareFun =>
136 | eat(LT.DeclareFun)
137 | def parseDecl: (SSymbol, Seq[Sort], Sort) = {
138 | val sym = parseSymbol
139 | val sorts = parseMany(() => parseSort)
140 | val resultSort = parseSort
141 | (sym, sorts, resultSort)
142 | }
143 | getPeekToken.kind match {
144 | case LT.OParen =>
145 | eat(LT.OParen)
146 | eat(LT.Par)
147 | val tps = parseMany(() => parseSymbol)
148 | val (sym, args, resultSort) = parseWithin(LT.OParen, LT.CParen)(() => parseDecl)
149 | eat(LT.CParen)
150 | DeclareFunPar(tps, sym, args, resultSort)
151 | case _ =>
152 | val (sym, args, resultSort) = parseDecl
153 | DeclareFun(sym, args, resultSort)
154 | }
155 |
156 | case LT.DefineFun =>
157 | eat(LT.DefineFun)
158 | getPeekToken.kind match {
159 | case LT.OParen =>
160 | eat(LT.OParen)
161 | eat(LT.Par)
162 | val tps = parseMany(() => parseSymbol)
163 | val funDef = parseWithin(LT.OParen, LT.CParen)(() => parseFunDef)
164 | eat(LT.CParen)
165 | DefineFunPar(tps, funDef)
166 |
167 | case _ =>
168 | val funDef = parseFunDef
169 | DefineFun(funDef)
170 | }
171 |
172 | case LT.DefineFunRec =>
173 | eat(LT.DefineFunRec)
174 | getPeekToken.kind match {
175 | case LT.OParen =>
176 | eat(LT.OParen)
177 | eat(LT.Par)
178 | val tps = parseMany(() => parseSymbol)
179 | val funDef = parseWithin(LT.OParen, LT.CParen)(() => parseFunDef)
180 | eat(LT.CParen)
181 | DefineFunRecPar(tps, funDef)
182 |
183 | case _ =>
184 | val funDef = parseFunDef
185 | DefineFunRec(funDef)
186 | }
187 |
188 | case LT.DefineFunsRec =>
189 | eat(LT.DefineFunsRec)
190 | val (funDec, funDecs) = parseOneOrMore(() => {
191 | eat(LT.OParen)
192 | val funDec = getPeekToken.kind match {
193 | case LT.Par =>
194 | eat(LT.Par)
195 | val tps = parseMany(() => parseSymbol)
196 | val funDec = parseWithin(LT.OParen, LT.CParen)(() => parseFunDec)
197 | Left(FunDecPar(tps, funDec.name, funDec.params, funDec.returnSort))
198 | case _ =>
199 | Right(parseFunDec)
200 | }
201 | eat(LT.CParen)
202 | funDec
203 | })
204 | val (body, bodies) = parseOneOrMore(() => parseTerm)
205 | assert(funDecs.size == bodies.size)
206 |
207 | if ((funDec +: funDecs).exists(_.isLeft)) {
208 | DefineFunsRecPar(funDec +: funDecs, body +: bodies)
209 | } else {
210 | def getRight(either: Either[FunDecPar, FunDec]) = either match {
211 | case Left(_) => throw new NoSuchElementException("getRight() on Left")
212 | case Right(a) => a
213 | }
214 |
215 | DefineFunsRec((funDec +: funDecs).map(getRight(_)), body +: bodies)
216 | }
217 |
218 | case LT.DeclareDatatypes =>
219 | eat(LT.DeclareDatatypes)
220 | val tps = parseMany(() => parseSymbol)
221 | val datatypes = parseMany(() => parseDatatypes)
222 | DeclareDatatypesPar(tps, datatypes)
223 |
224 | case _ => super.parseCommandWithoutParens
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/extensions/tip/Trees.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package extensions.tip
3 |
4 | import printer._
5 | import trees.Terms._
6 | import trees.Commands._
7 | import trees.TreeTransformer
8 |
9 | object Terms {
10 | case class Lambda(args: Seq[SortedVar], body: Term) extends TermExtension {
11 | def print(ctx: PrintingContext): Unit = {
12 | ctx.print("(lambda ")
13 | ctx.printNary(args, "(", " ", ") ")
14 | ctx.print(body)
15 | ctx.print(")")
16 | }
17 | }
18 |
19 | case class Application(caller: Term, args: Seq[Term]) extends TermExtension {
20 | def print(ctx: PrintingContext): Unit = {
21 | ctx.print("(@ ")
22 | ctx.printNary(caller +: args, "", " ", ")")
23 | }
24 | }
25 |
26 | case class Match(scrut: Term, cases: Seq[Case]) extends TermExtension {
27 | def print(ctx: PrintingContext): Unit = {
28 | ctx.print("(match ")
29 | ctx.print(scrut)
30 | ctx.printNary(cases, (cse: Case) => {
31 | ctx.print("(case ")
32 | cse.pattern match {
33 | case Default => ctx.print("default")
34 | case CaseObject(sym) => ctx.print(sym)
35 | case CaseClass(sym, args) => ctx.printNary(sym +: args, "(", " ", ")")
36 | }
37 | ctx.print(" ")
38 | ctx.print(cse.rhs)
39 | ctx.print(")")
40 | }, " ", " ", ")")
41 | }
42 | }
43 |
44 | case class Case(pattern: Pattern, rhs: Term)
45 |
46 | sealed trait Pattern
47 | case object Default extends Pattern
48 | case class CaseObject(sym: SSymbol) extends Pattern
49 | case class CaseClass(sym: SSymbol, binders: Seq[SSymbol]) extends Pattern
50 |
51 | case class FunDecPar(tps: Seq[SSymbol], name: SSymbol, params: Seq[SortedVar], returnSort: Sort)
52 | }
53 |
54 | object Commands {
55 | import Terms._
56 |
57 | case class AssertPar(tps: Seq[SSymbol], term: Term) extends CommandExtension {
58 | def print(ctx: PrintingContext): Unit = {
59 | ctx.print("(assert (par ")
60 | ctx.printNary(tps, "(", " ", ") ")
61 | ctx.print(term)
62 | ctx.print("))\n")
63 | }
64 | def transform(tt: TreeTransformer)(context: tt.C): (Command, tt.R) = ???
65 | }
66 |
67 | case class DeclareConstPar(tps: Seq[SSymbol], sym: SSymbol, sort: Sort) extends CommandExtension {
68 | def print(ctx: PrintingContext): Unit = {
69 | ctx.print("(declare-const (par ")
70 | ctx.printNary(tps, "(", " ", ") ")
71 | ctx.print("(")
72 | ctx.print(sym)
73 | ctx.print(" ")
74 | ctx.print(sort)
75 | ctx.print(")))\n")
76 | }
77 | def transform(tt: TreeTransformer)(context: tt.C): (Command, tt.R) = ???
78 | }
79 |
80 | case class DeclareFunPar(tps: Seq[SSymbol], sym: SSymbol, argSorts: Seq[Sort], returnSort: Sort) extends CommandExtension {
81 | def print(ctx: PrintingContext): Unit = {
82 | ctx.print("(declare-fun (par ")
83 | ctx.printNary(tps, "(", " ", ") ")
84 | ctx.print("(")
85 | ctx.print(sym)
86 | ctx.printNary(argSorts, " (", " ", ") ")
87 | ctx.print(returnSort)
88 | ctx.print(")))\n")
89 | }
90 | def transform(tt: TreeTransformer)(context: tt.C): (Command, tt.R) = ???
91 | }
92 |
93 | case class DefineFunPar(tps: Seq[SSymbol], fd: FunDef) extends CommandExtension {
94 | def print(ctx: PrintingContext): Unit = {
95 | ctx.print("(define-fun (par ")
96 | ctx.printNary(tps, "(", " ", ") ")
97 | ctx.print("(")
98 | ctx.print(fd.name)
99 | ctx.printNary(fd.params, " (", " ", ") ")
100 | ctx.print(fd.returnSort)
101 | ctx.print(" ")
102 | ctx.print(fd.body)
103 | ctx.print(")))\n")
104 | }
105 | def transform(tt: TreeTransformer)(context: tt.C): (Command, tt.R) = ???
106 | }
107 |
108 | case class DefineFunRecPar(tps: Seq[SSymbol], fd: FunDef) extends CommandExtension {
109 | def print(ctx: PrintingContext): Unit = {
110 | ctx.print("(define-fun-rec (par ")
111 | ctx.printNary(tps, "(", " ", ") ")
112 | ctx.print("(")
113 | ctx.print(fd.name)
114 | ctx.printNary(fd.params, " (", " ", ") ")
115 | ctx.print(fd.returnSort)
116 | ctx.print(" ")
117 | ctx.print(fd.body)
118 | ctx.print(")))\n")
119 | }
120 | def transform(tt: TreeTransformer)(context: tt.C): (Command, tt.R) = ???
121 | }
122 |
123 | case class DefineFunsRecPar(fds: Seq[Either[FunDecPar, FunDec]], bodies: Seq[Term]) extends CommandExtension {
124 | def print(ctx: PrintingContext): Unit = {
125 | ctx.print("(define-funs-rec ")
126 | ctx.printNary(fds, (fd: Either[FunDecPar, FunDec]) => fd match {
127 | case Left(FunDecPar(tps, name, params, returnSort)) =>
128 | ctx.print("(par ")
129 | ctx.printNary(tps, "(", " ", ") ")
130 | ctx.print("(")
131 | ctx.print(name)
132 | ctx.printNary(params, " (", " ", ") ")
133 | ctx.print(returnSort)
134 | ctx.print("))")
135 | case Right(FunDec(name, params, returnSort)) =>
136 | ctx.print("(")
137 | ctx.print(name)
138 | ctx.printNary(params, " (", " ", ") ")
139 | ctx.print(returnSort)
140 | ctx.print(")")
141 | }, "(", " ", ") ")
142 | ctx.printNary(bodies, "(", " ", "))\n")
143 | }
144 | def transform(tt: TreeTransformer)(context: tt.C): (Command, tt.R) = ???
145 | }
146 |
147 | case class DeclareDatatypesPar(tps: Seq[SSymbol], datatypes: Seq[(SSymbol, Seq[Constructor])]) extends CommandExtension {
148 | def print(ctx: PrintingContext): Unit = {
149 | ctx.print("(declare-datatypes ")
150 | ctx.printNary(tps, "(", " ", ") ")
151 | ctx.printNary(datatypes, (datatype: (SSymbol, Seq[Constructor])) => {
152 | ctx.print("(")
153 | ctx.print(datatype._1.name)
154 | if (datatype._2.nonEmpty) ctx.printNary(datatype._2, (constructor: Constructor) => {
155 | ctx.print("(")
156 | ctx.print(constructor.sym.name)
157 | if (constructor.fields.nonEmpty) ctx.printNary(constructor.fields, (field: (SSymbol, Sort)) => {
158 | ctx.print("(")
159 | ctx.print(field._1.name)
160 | ctx.print(" ")
161 | ctx.print(field._2)
162 | ctx.print(")")
163 | }, " ", " ", "")
164 | ctx.print(")")
165 | }, " ", " ", "")
166 | ctx.print(")")
167 | }, "(", " ", "))\n")
168 | }
169 | def transform(tt: TreeTransformer)(context: tt.C): (Command, tt.R) = ???
170 | }
171 | }
172 |
173 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/interpreters/CVC4Interpreter.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package interpreters
3 |
4 | import trees.Terms._
5 | import trees.Commands._
6 | import trees.CommandsResponses._
7 |
8 | class CVC4Interpreter(executable: String, args: Array[String], tailPrinter: Boolean = false)
9 | extends ProcessInterpreter(executable, args, tailPrinter) {
10 |
11 | printer.printCommand(SetOption(PrintSuccess(true)), in)
12 | in.write("\n")
13 | in.flush
14 | parser.parseGenResponse
15 |
16 | }
17 |
18 | object CVC4Interpreter {
19 |
20 | def buildDefault: CVC4Interpreter = {
21 | val executable = "cvc4"
22 | val args = Array("-q",
23 | "-i",
24 | "--produce-models",
25 | "--dt-rewrite-error-sel",
26 | "--print-success",
27 | "--lang", "smt2.5")
28 | new CVC4Interpreter(executable, args)
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/interpreters/ProcessInterpreter.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package interpreters
3 |
4 | import lexer.Lexer
5 | import parser.Parser
6 | import trees.Terms._
7 | import trees.Commands._
8 | import trees.CommandsResponses._
9 | import printer._
10 |
11 | import java.io._
12 |
13 | abstract class ProcessInterpreter(protected val process: Process, tailPrinter: Boolean) extends Interpreter {
14 |
15 | def this(executable: String, args: Array[String], tailPrinter: Boolean = false) = {
16 | this(java.lang.Runtime.getRuntime.exec((executable :: args.toList).mkString(" ")), tailPrinter)
17 | }
18 |
19 | lazy val in = new BufferedWriter(new OutputStreamWriter(process.getOutputStream))
20 | lazy val out = new BufferedReader(new InputStreamReader(process.getInputStream))
21 |
22 | lazy val parser: Parser = new Parser(new Lexer(out))
23 | lazy val printer: Printer = if (tailPrinter) TailPrinter else RecursivePrinter
24 |
25 | def parseResponseOf(cmd: SExpr): SExpr = cmd match {
26 | case CheckSat() => parser.parseCheckSatResponse
27 | case GetAssertions() => parser.parseGetAssertionsResponse
28 | case GetUnsatCore() => parser.parseGetUnsatCoreResponse
29 | case GetUnsatAssumptions() => parser.parseGetUnsatAssumptionsResponse
30 | case GetProof() => parser.parseGetProofResponse
31 | case GetValue(_, _) => parser.parseGetValueResponse
32 | case GetAssignment() => parser.parseGetAssignmentResponse
33 |
34 | case GetOption(_) => parser.parseGetOptionResponse
35 | case GetInfo(_) => parser.parseGetInfoResponse
36 |
37 | case GetModel() => parser.parseGetModelResponse
38 |
39 | case (_: Command) => parser.parseGenResponse
40 |
41 | //in the case the input was not a known command, we assume nothing and
42 | //parse an arbitrary s-expr
43 | case _ => parser.parseSExpr
44 | }
45 |
46 | /*
47 | * eval is blocking, and not synchronized. You
48 | * should not invoke eval from different threads.
49 | */
50 | override def eval(cmd: SExpr): SExpr = {
51 | try {
52 | printer.printSExpr(cmd, in)
53 | in.write("\n")
54 | in.flush
55 |
56 | parseResponseOf(cmd)
57 | } catch {
58 | case (ex: Exception) => {
59 | if(cmd == CheckSat()) CheckSatStatus(UnknownStatus)
60 | else Error("Solver encountered exception: " + ex)
61 | }
62 | }
63 | }
64 |
65 | private var isKilled = false
66 |
67 | override def free(): Unit = synchronized {
68 | if(!isKilled) {
69 | try {
70 | printer.printCommand(Exit(), in)
71 | in.write("\n")
72 | in.flush
73 |
74 | process.destroyForcibly()
75 | in.close()
76 | } catch {
77 | case (io: java.io.IOException) => ()
78 | } finally {
79 | isKilled = true
80 | try { in.close() } catch { case (io: java.io.IOException) => () }
81 | }
82 | }
83 | }
84 |
85 | def kill(): Unit = synchronized {
86 | if(!isKilled) {
87 | try {
88 | process.destroyForcibly()
89 | in.close()
90 | } catch {
91 | case (io: java.io.IOException) => ()
92 | } finally {
93 | isKilled = true
94 | }
95 | }
96 | }
97 |
98 | override def interrupt(): Unit = synchronized {
99 | kill()
100 | }
101 |
102 | /*
103 | * Manos, greatest hack:
104 | * Process.destroyForcibly is only available on java8,
105 | * Using the implicit conversion, if compiled with java7
106 | * we will fallback to Process.destroy. If compiled on java8,
107 | * it will ignore the implicit conversion as the method exists,
108 | * and call the native Process.destroyForcibly.
109 | */
110 | private implicit class Java8Process(process: Process) {
111 | def destroyForcibly() = process.destroy
112 | }
113 |
114 | }
115 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/interpreters/Z3Interpreter.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package interpreters
3 |
4 | import trees.Commands._
5 | import printer.RecursivePrinter
6 |
7 | class Z3Interpreter(executable: String, args: Array[String], tailPrinter: Boolean = false)
8 | extends ProcessInterpreter(executable, args, tailPrinter) {
9 |
10 | printer.printCommand(SetOption(PrintSuccess(true)), in)
11 | in.write("\n")
12 | in.flush
13 | parser.parseGenResponse
14 |
15 | }
16 |
17 | object Z3Interpreter {
18 |
19 | def buildDefault: Z3Interpreter = {
20 | val executable = "z3"
21 | val args = Array("-in", "-smt2")
22 | new Z3Interpreter(executable, args)
23 | }
24 |
25 | def buildForV3: Z3Interpreter = {
26 | val executable = "z3"
27 | val args = Array("-in", "-m", "-smt2")
28 | new Z3Interpreter(executable, args)
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/lexer/Lexer.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package lexer
3 |
4 | import Tokens._
5 | import common._
6 |
7 | import scala.collection.mutable.ListBuffer
8 |
9 | class Lexer(reader: java.io.Reader) {
10 |
11 | import Lexer._
12 |
13 | private def isNewLine(c: Char) = c == '\n' || c == '\r'
14 | private def isBlank(c: Char) = c == '\n' || c == '\r' || c == ' '
15 |
16 | /*
17 | * Note that we do not start reading the input until the next function is called.
18 | */
19 | private var _currentChar: Int = -1
20 | private var _futureChar: Option[Int] = None
21 |
22 | /*
23 | * Current line and column numbers of the current char value
24 | */
25 | private var _currentLine: Int = 1
26 | private var _currentCol: Int = 0
27 |
28 | /*
29 | * nextChar reads the next char in the reader and convert it into a char.
30 | * It raises an unexceptedEOFException if EOF is reached in the reader
31 | */
32 | private def nextChar: Char = {
33 | _futureChar match {
34 | case Some(i) => {
35 | if(i == -1)
36 | throw new UnexpectedEOFException(Position(_currentLine, _currentCol))
37 | _currentChar = i
38 | _futureChar = None
39 | }
40 | case None => {
41 | try {
42 | _currentChar = reader.read
43 | } catch {
44 | case e: java.io.EOFException =>
45 | throw new UnexpectedEOFException(Position(_currentLine, _currentCol))
46 | }
47 | if(_currentChar == -1)
48 | throw new UnexpectedEOFException(Position(_currentLine, _currentCol))
49 | }
50 | }
51 |
52 | val res = _currentChar.toChar
53 | if(isNewLine(res)) {
54 | _currentLine += 1
55 | _currentCol = 0
56 | } else {
57 | _currentCol += 1
58 | }
59 | res
60 | }
61 |
62 | //peek assumes that there should be something to read, encountering eof
63 | //should return -1, and the call should not be blocking
64 | private def peek: Int = _futureChar match {
65 | case Some(i) => i
66 | case None => {
67 | try {
68 | val tmp = reader.read
69 | _futureChar = Some(tmp)
70 | tmp
71 | } catch {
72 | case e: java.io.EOFException => -1
73 | }
74 | }
75 | }
76 |
77 | /*
78 | * Return the next token if there is one, or null if EOF
79 | */
80 | def nextToken: Token = if(peek == -1) null else {
81 |
82 | var c: Char = nextChar
83 |
84 | while(isBlank(c) || c == ';') {
85 |
86 | if(c == ';') {
87 | while(!isNewLine(c)) {
88 | if(peek == -1)
89 | return null
90 | c = nextChar
91 | }
92 | }
93 |
94 | while(isBlank(c)) {
95 | if(peek == -1)
96 | return null
97 | c = nextChar
98 | }
99 |
100 | }
101 |
102 | val currentPosition = Position(_currentLine, _currentCol)
103 |
104 | val res: Token = c match {
105 | case '(' => Token(OParen)
106 | case ')' => Token(CParen)
107 | case ':' => Keyword(readSymbol(nextChar))
108 | case '"' => {
109 | val buffer = new scala.collection.mutable.ArrayBuffer[Char]
110 | var c = nextChar
111 | while(c != '"' || peek == '"') {
112 | if(c == '"') {
113 | assert(peek == '"')
114 | c = nextChar
115 | }
116 | buffer.append(c)
117 | c = nextChar
118 | }
119 | StringLit(new String(buffer.toArray))
120 | }
121 | case '#' => {
122 | nextChar match {
123 | case 'b' => BinaryLit(readBinary())
124 | case 'x' => HexadecimalLit(readHexadecimal())
125 | case c => {
126 | throw new UnexpectedCharException(c,
127 | Position(_currentLine, _currentCol),
128 | "'#' should be followed by a radix 'b' or 'x'")
129 | }
130 | }
131 | }
132 | case d if d.isDigit => {
133 | val intPart = readInt(d, 10)
134 | if(peek != '.')
135 | NumeralLit(intPart)
136 | else {
137 | nextChar
138 | var fracPart: Double = 0
139 | var base = 10
140 | while(peek.toChar.isDigit) {
141 | fracPart += nextChar.asDigit
142 | fracPart *= 10
143 | base *= 10
144 | }
145 | DecimalLit(intPart.toDouble + fracPart/base)
146 | }
147 | }
148 | case s if isSymbolChar(s) || s == '|' => { //this case is after digits, since a symbol cannot start with a digit
149 | val sym = readSymbol(s)
150 | val res = toReserved(sym)
151 | res.getOrElse(SymbolLit(sym))
152 | }
153 | case c => {
154 | throw new UnexpectedCharException(c,
155 | Position(_currentLine, _currentCol),
156 | "not a valid start for a token")
157 | }
158 | }
159 |
160 | res.setPos(currentPosition)
161 | }
162 |
163 | /*
164 | * Parse a symbol that can possibly starts with a digit.
165 | */
166 | //if this gets called for a full symbol, then we know that current char cannot be a
167 | //digit and hence we can ignore that case. If it gets called from keyword case, then
168 | //it might be a digit and this is fine according to the standard
169 | private def readSymbol(currentChar: Char): String = {
170 | val buffer = new scala.collection.mutable.ArrayBuffer[Char]
171 | if(currentChar == '|') { //a symbol can be within quotes: |symb|
172 | var c = nextChar
173 | while(c != '|') {
174 | if(c == '\\')
175 | throw new UnexpectedCharException(c,
176 | Position(_currentLine, _currentCol),
177 | "Quoted symbols cannot contain backslashes")
178 | buffer.append(c)
179 | c = nextChar
180 | }
181 | } else {
182 | buffer.append(currentChar)
183 | while(isSymbolChar(peek.toChar)) {
184 | buffer.append(nextChar)
185 | }
186 | }
187 | new String(buffer.toArray)
188 | }
189 |
190 | private def readInt(currentChar: Char, r: Int): BigInt = {
191 | require(r > 1 && r <= 36)
192 |
193 | val pos = Position(_currentLine, _currentCol)
194 |
195 | var literal: String = currentChar.toString
196 | var acc: BigInt = currentChar.asDigit //asDigit works for 'A', 'F', ...
197 | while(isDigit(peek.toChar, r)) {
198 | acc *= r
199 | val c = nextChar
200 | acc += c.asDigit
201 | literal += c.toString
202 | }
203 |
204 | if(literal.head == '0' && literal.size > 1)
205 | throw new IllegalTokenException(literal, pos, "Numeral should not have leading 0")
206 |
207 | acc
208 | }
209 |
210 | private def readBinary(): Seq[Boolean] = {
211 | val res = new ListBuffer[Boolean]
212 | if(peek != '1' && peek != '0')
213 | throw new Exception
214 | while(peek == '1' || peek == '0') {
215 | res.append(if(peek == '1') true else false)
216 | nextChar
217 | }
218 | res.toList
219 | }
220 |
221 | private def readHexadecimal(): Hexadecimal = {
222 | var res = ""
223 | if(peek == -1 || !isHexa(peek.toChar))
224 | throw new Exception
225 | while(peek != -1 && isHexa(peek.toChar)) {
226 | res += nextChar.toUpper
227 | }
228 | Hexadecimal.fromString(res).get
229 | }
230 |
231 |
232 | protected def toReserved(s: String): Option[Token] = {
233 | val str2tok: PartialFunction[String, Token] = {
234 | case "BINARY" => Token(BINARY)
235 | case "DECIMAL" => Token(DECIMAL)
236 | case "HEXADECIMAL" => Token(HEXADECIMAL)
237 | case "NUMERAL" => Token(NUMERAL)
238 | case "STRING" => Token(STRING)
239 | case "_" => Token(Underscore)
240 | case "!" => Token(ExclamationMark)
241 | case "as" => Token(As)
242 | case "let" => Token(Let)
243 | case "forall" => Token(Forall)
244 | case "exists" => Token(Exists)
245 | case "par" => Token(Par)
246 |
247 | case "assert" => Token(Assert)
248 | case "check-sat" => Token(CheckSat)
249 | case "check-sat-assuming" => Token(CheckSatAssuming)
250 | case "declare-const" => Token(DeclareConst)
251 | case "declare-fun" => Token(DeclareFun)
252 | case "declare-sort" => Token(DeclareSort)
253 | case "define-fun" => Token(DefineFun)
254 | case "define-fun-rec" => Token(DefineFunRec)
255 | case "define-funs-rec" => Token(DefineFunsRec)
256 | case "define-sort" => Token(DefineSort)
257 | case "echo" => Token(Echo)
258 | case "exit" => Token(Exit)
259 | case "get-assertions" => Token(GetAssertions)
260 | case "get-assignment" => Token(GetAssignment)
261 | case "get-info" => Token(GetInfo)
262 | case "get-model" => Token(GetModel)
263 | case "get-option" => Token(GetOption)
264 | case "get-proof" => Token(GetProof)
265 | case "get-unsat-assumptions" => Token(GetUnsatAssumptions)
266 | case "get-unsat-core" => Token(GetUnsatCore)
267 | case "get-value" => Token(GetValue)
268 | case "pop" => Token(Pop)
269 | case "push" => Token(Push)
270 | case "reset" => Token(Reset)
271 | case "reset-assertions" => Token(ResetAssertions)
272 | case "set-info" => Token(SetInfo)
273 | case "set-logic" => Token(SetLogic)
274 | case "set-option" => Token(SetOption)
275 |
276 | case "declare-datatypes" => Token(DeclareDatatypes)
277 | }
278 | str2tok.lift(s)
279 | }
280 |
281 | }
282 |
283 | object Lexer {
284 |
285 | class UnexpectedCharException(val char: Char, val position: Position, val msg: String) extends
286 | Exception("Encountered unexpected character: '" + char + "' at " + position + ": " + msg)
287 |
288 | class UnexpectedEOFException(val position: Position) extends Exception
289 |
290 | class IllegalTokenException(val token: String, val position: Position, msg: String) extends Exception(s"Illegal token [$token] at $position: $msg")
291 |
292 |
293 | private val extraSymbolChars = Set('+', '-', '*', '/', '@', '$', '%', '^', '&',
294 | '_', '!', '?', '=', '<', '>', '~', '.')
295 |
296 | def isSymbolChar(c: Char): Boolean =
297 | c.isDigit || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || extraSymbolChars.contains(c)
298 |
299 | def isHexa(c: Char): Boolean =
300 | c.isDigit || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')
301 |
302 |
303 | /* if c is digit in radix r (1 < r <= 36) */
304 | def isDigit(c: Char, r: Int): Boolean = {
305 | require(r > 1 && r <= 36)
306 | val d = (c - '0')
307 | if(d < 10 && d >= 0)
308 | d < r
309 | else {
310 | val ld = (c.toLower - 'a')
311 | ld >= 0 && ld < r - 10
312 | }
313 | }
314 | }
315 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/lexer/Tokens.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package lexer
3 |
4 | import common._
5 |
6 | object Tokens {
7 |
8 | sealed class Token(val kind: TokenKind) extends Positioned {
9 | override def toString = kind.toString
10 | }
11 |
12 | object Token {
13 | def apply(kind: TokenKind): Token = new Token(kind)
14 | def unapply(token: Token): Option[TokenKind] = Some(token.kind)
15 | }
16 |
17 | case class StringLit(content: String) extends Token(StringLitKind) {
18 | override def toString = "\"" + content + "\""
19 | }
20 | case class SymbolLit(content: String) extends Token(SymbolLitKind) {
21 | override def toString = s"$content"
22 | }
23 | case class Keyword(name: String) extends Token(KeywordKind) {
24 | override def toString = s":$name"
25 | }
26 |
27 | case class NumeralLit(n: BigInt) extends Token(NumeralLitKind) {
28 | override def toString = n.toString
29 | }
30 | case class DecimalLit(d: Double) extends Token(DecimalLitKind) {
31 | override def toString = d.toString
32 | }
33 | case class BinaryLit(content: Seq[Boolean]) extends Token(BinaryLitKind) {
34 | override def toString = content.map(d => if(d) "1" else "0").mkString
35 | }
36 | case class HexadecimalLit(content: Hexadecimal) extends Token(HexadecimalLitKind) {
37 | override def toString = content.toString
38 | }
39 |
40 | sealed trait TokenKind
41 |
42 | case object OParen extends TokenKind /* ( */
43 | case object CParen extends TokenKind /* ) */
44 |
45 | case object StringLitKind extends TokenKind /* "hello" */
46 | case object SymbolLitKind extends TokenKind /* hello */
47 | case object KeywordKind extends TokenKind /* :bar */
48 | case object NumeralLitKind extends TokenKind /* 42 */
49 | case object DecimalLitKind extends TokenKind /* 42.24 */
50 | case object BinaryLitKind extends TokenKind /* #b0101 */
51 | case object HexadecimalLitKind extends TokenKind /* #xFF1D */
52 |
53 | trait ReservedWord extends TokenKind
54 | case object BINARY extends ReservedWord
55 | case object DECIMAL extends ReservedWord
56 | case object HEXADECIMAL extends ReservedWord
57 | case object NUMERAL extends ReservedWord
58 | case object STRING extends ReservedWord
59 | case object Underscore extends ReservedWord /* _ */
60 | case object ExclamationMark extends ReservedWord /* ! */
61 | case object As extends ReservedWord /* as */
62 | case object Let extends ReservedWord /* let */
63 | case object Forall extends ReservedWord /* forall */
64 | case object Exists extends ReservedWord /* exists */
65 | case object Par extends ReservedWord
66 |
67 | case object Assert extends ReservedWord
68 | case object CheckSat extends ReservedWord
69 | case object CheckSatAssuming extends ReservedWord
70 | case object DeclareConst extends ReservedWord
71 | case object DeclareFun extends ReservedWord
72 | case object DeclareSort extends ReservedWord
73 | case object DefineFun extends ReservedWord
74 | case object DefineFunRec extends ReservedWord
75 | case object DefineFunsRec extends ReservedWord
76 | case object DefineSort extends ReservedWord
77 | case object Echo extends ReservedWord
78 | case object Exit extends ReservedWord
79 | case object GetAssertions extends ReservedWord
80 | case object GetAssignment extends ReservedWord
81 | case object GetInfo extends ReservedWord
82 | case object GetModel extends ReservedWord
83 | case object GetOption extends ReservedWord
84 | case object GetProof extends ReservedWord
85 | case object GetUnsatAssumptions extends ReservedWord
86 | case object GetUnsatCore extends ReservedWord
87 | case object GetValue extends ReservedWord
88 | case object Pop extends ReservedWord
89 | case object Push extends ReservedWord
90 | case object Reset extends ReservedWord
91 | case object ResetAssertions extends ReservedWord
92 | case object SetInfo extends ReservedWord
93 | case object SetLogic extends ReservedWord
94 | case object SetOption extends ReservedWord
95 |
96 | case object DeclareDatatypes extends ReservedWord
97 |
98 | def reservedToSymbol(word: ReservedWord): String = word match {
99 | case BINARY => "BINARY"
100 | case DECIMAL => "DECIMAL"
101 | case HEXADECIMAL => "HEXADECIMAl"
102 | case NUMERAL => "NUMERAL"
103 | case STRING => "STRING"
104 | case Underscore => "_"
105 | case ExclamationMark => "!"
106 | case As => "as"
107 | case Let => "let"
108 | case Forall => "forall"
109 | case Exists => "exists"
110 | case Par => "par"
111 |
112 | case Assert => "assert"
113 | case CheckSat => "check-sat"
114 | case CheckSatAssuming => "check-sat-assuming"
115 | case DeclareConst => "declare-const"
116 | case DeclareFun => "declare-fun"
117 | case DeclareSort => "ddeclare-sort"
118 | case DefineFun => "define-fun"
119 | case DefineFunRec => "define-fun-rec"
120 | case DefineFunsRec => "define-funs-rec"
121 | case DefineSort => "define-sort"
122 | case Echo => "echo"
123 | case Exit => "exit"
124 | case GetAssertions => "get-assertions"
125 | case GetAssignment => "get-assignment"
126 | case GetInfo => "get-info"
127 | case GetModel => "get-model"
128 | case GetOption => "get-option"
129 | case GetProof => "get-proof"
130 | case GetUnsatAssumptions => "get-unsat-assumptions"
131 | case GetUnsatCore => "get-unsat-core"
132 | case GetValue => "get-value"
133 | case Pop => "pop"
134 | case Push => "push"
135 | case Reset => "reset"
136 | case ResetAssertions => "reset-assetions"
137 | case SetInfo => "set-info"
138 | case SetLogic => "set-logic"
139 | case SetOption => "set-option"
140 |
141 | case DeclareDatatypes => "declare-datatypes"
142 |
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/parser/Parser.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package parser
3 |
4 | import lexer.Tokens
5 | import Tokens.{Token, TokenKind}
6 | import lexer.Lexer
7 |
8 | class Parser(val lexer: Lexer) extends ParserCommon with ParserTerms with ParserCommands with ParserCommandsResponses
9 |
10 | object Parser {
11 |
12 | class UnknownCommandException(val commandName: TokenKind) extends Exception("Unknown command name token: " + commandName)
13 |
14 | class UnexpectedTokenException(found: Token, expected: Seq[TokenKind])
15 | extends Exception("Unexpected token at position: " + found.getPos + ". Expected: " + expected.mkString("[",",","]") + ". Found: " + found)
16 |
17 | class UnexpectedEOFException(expected: Seq[TokenKind])
18 | extends Exception("Unexpected end of file. Expected: " + expected.mkString("[",",","]"))
19 |
20 | def fromString(str: String): Parser = {
21 | val lexer = new Lexer(new java.io.StringReader(str))
22 | new Parser(lexer)
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/parser/ParserCommands.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package parser
3 |
4 | import lexer.Tokens
5 | import trees.Terms._
6 | import trees.Commands._
7 |
8 | import scala.collection.mutable.ListBuffer
9 |
10 | trait ParserCommands { this: ParserCommon with ParserTerms =>
11 |
12 | import Parser._
13 |
14 | def parseScript: Script = {
15 |
16 | val cmds = new ListBuffer[Command]()
17 | var cmd = parseCommand
18 | while(cmd != null) {
19 | cmds.append(cmd)
20 | cmd = parseCommand
21 | }
22 | Script(cmds.toList)
23 | }
24 |
25 | protected def parseCommandWithoutParens: Command = nextToken().kind match {
26 | case Tokens.Assert => {
27 | Assert(parseTerm)
28 | }
29 | case Tokens.CheckSat => CheckSat()
30 | case Tokens.CheckSatAssuming => {
31 | val props = parseMany(() => parsePropLit)
32 | CheckSatAssuming(props)
33 | }
34 |
35 | case Tokens.DeclareConst => {
36 | val name = parseSymbol
37 | val sort = parseSort
38 | DeclareConst(name, sort)
39 | }
40 | case Tokens.DeclareFun => {
41 | val sym = parseSymbol
42 |
43 | val params = new ListBuffer[Sort]
44 | eat(Tokens.OParen)
45 | while(peekToken.kind != Tokens.CParen)
46 | params.append(parseSort)
47 | eat(Tokens.CParen)
48 |
49 | val sort = parseSort
50 | DeclareFun(sym, params.toList, sort)
51 | }
52 | case Tokens.DeclareSort => {
53 | val sym = parseSymbol
54 | val arity = parseNumeral
55 | DeclareSort(sym, arity.value.toInt)
56 | }
57 |
58 | case Tokens.DefineFun => {
59 | val funDef = parseFunDef
60 | DefineFun(funDef)
61 | }
62 | case Tokens.DefineFunRec => {
63 | val funDef = parseFunDef
64 | DefineFunRec(funDef)
65 | }
66 | case Tokens.DefineFunsRec => {
67 | val (funDef, funDefs) = parseOneOrMore(() => parseWithin(Tokens.OParen, Tokens.CParen)(() => parseFunDec))
68 | val (body, bodies) = parseOneOrMore(() => parseTerm)
69 | assert(funDefs.size == bodies.size)
70 | DefineFunsRec(funDef +: funDefs, body +: bodies)
71 | }
72 | case Tokens.DefineSort => {
73 | val sym = parseSymbol
74 |
75 | val vars = new ListBuffer[SSymbol]
76 | eat(Tokens.OParen)
77 | while(peekToken.kind != Tokens.CParen)
78 | vars.append(parseSymbol)
79 | eat(Tokens.CParen)
80 |
81 | val sort = parseSort
82 | DefineSort(sym, vars.toList, sort)
83 | }
84 |
85 | case Tokens.Echo => {
86 | val value = parseString
87 | Echo(value)
88 | }
89 | case Tokens.Exit => Exit()
90 |
91 | case Tokens.GetAssertions => GetAssertions()
92 | case Tokens.GetAssignment => GetAssignment()
93 |
94 | case Tokens.GetInfo => {
95 | val infoFlag = parseInfoFlag
96 | GetInfo(infoFlag)
97 | }
98 |
99 | case Tokens.GetModel => GetModel()
100 |
101 | case Tokens.GetOption => {
102 | val keyword = parseKeyword
103 | GetOption(keyword)
104 | }
105 |
106 | case Tokens.GetProof => GetProof()
107 | case Tokens.GetUnsatAssumptions => GetUnsatAssumptions()
108 | case Tokens.GetUnsatCore => GetUnsatCore()
109 |
110 | case Tokens.GetValue => {
111 | eat(Tokens.OParen)
112 | val ts = new ListBuffer[Term]
113 | while(peekToken.kind != Tokens.CParen)
114 | ts.append(parseTerm)
115 | eat(Tokens.CParen)
116 | GetValue(ts.head, ts.tail.toList)
117 | }
118 |
119 | case Tokens.Pop => {
120 | val n = parseNumeral
121 | Pop(n.value.toInt)
122 | }
123 | case Tokens.Push => {
124 | val n = parseNumeral
125 | Push(n.value.toInt)
126 | }
127 |
128 | case Tokens.Reset => Reset()
129 | case Tokens.ResetAssertions => ResetAssertions()
130 |
131 | case Tokens.SetInfo => {
132 | SetInfo(parseAttribute)
133 | }
134 |
135 | case Tokens.SetLogic => {
136 | val logicSymbol: SSymbol = parseSymbol
137 | val logic: Logic =
138 | Logic.standardLogicFromString.lift(logicSymbol.name).getOrElse({
139 | logicSymbol match {
140 | case SSymbol("ALL") => ALL()
141 | case _ => NonStandardLogic(logicSymbol)
142 | }
143 | })
144 | SetLogic(logic.setPos(logicSymbol))
145 | }
146 | case Tokens.SetOption => {
147 | SetOption(parseOption)
148 | }
149 |
150 | case Tokens.DeclareDatatypes => {
151 | eat(Tokens.OParen)
152 | eat(Tokens.CParen)
153 |
154 | val datatypes = parseMany(() => parseDatatypes)
155 |
156 | DeclareDatatypes(datatypes)
157 | }
158 |
159 | case kind => {
160 | throw new UnknownCommandException(kind)
161 | }
162 | }
163 |
164 | def parseCommand: Command = if(peekToken == null) null else {
165 | val head = nextToken()
166 | check(head, Tokens.OParen)
167 | val cmd = parseCommandWithoutParens
168 | eat(Tokens.CParen)
169 |
170 | cmd.setPos(head)
171 | }
172 |
173 | def parsePropLit: PropLiteral = {
174 | peekToken.kind match {
175 | case Tokens.SymbolLitKind => {
176 | val sym = parseSymbol
177 | PropLiteral(sym, true).setPos(sym)
178 | }
179 | case Tokens.OParen => {
180 | val start = eat(Tokens.OParen)
181 | eat(Tokens.SymbolLit("not"))
182 | val sym = parseSymbol
183 | eat(Tokens.CParen)
184 | PropLiteral(sym, false).setPos(start)
185 | }
186 | case _ => {
187 | expected(peekToken, Tokens.SymbolLitKind, Tokens.OParen)
188 | }
189 | }
190 | }
191 |
192 | def parseFunDec: FunDec = {
193 | val name = parseSymbol
194 |
195 | val sortedVars = parseMany(() => parseSortedVar)
196 |
197 | val sort = parseSort
198 |
199 | FunDec(name, sortedVars, sort)
200 | }
201 |
202 | def parseFunDef: FunDef = {
203 | val name = parseSymbol
204 |
205 | val sortedVars = parseMany(() => parseSortedVar)
206 |
207 | val sort = parseSort
208 |
209 | val body = parseTerm
210 |
211 | FunDef(name, sortedVars, sort, body)
212 | }
213 |
214 | def parseDatatypes: (SSymbol, Seq[Constructor]) = {
215 | eat(Tokens.OParen)
216 | val name = parseSymbol
217 | val constructors = new ListBuffer[Constructor]
218 | while(peekToken.kind != Tokens.CParen) {
219 | constructors.append(parseConstructor)
220 | }
221 | eat(Tokens.CParen)
222 | (name, constructors.toSeq)
223 | }
224 |
225 | def parseConstructor: Constructor = {
226 | eat(Tokens.OParen)
227 | val name = parseSymbol
228 |
229 | val fields = new ListBuffer[(SSymbol, Sort)]
230 | while(peekToken.kind != Tokens.CParen) {
231 | eat(Tokens.OParen)
232 | val fieldName = parseSymbol
233 | val fieldSort = parseSort
234 | eat(Tokens.CParen)
235 | fields.append((fieldName, fieldSort))
236 | }
237 | eat(Tokens.CParen)
238 |
239 | Constructor(name, fields.toList)
240 | }
241 |
242 |
243 | def parseInfoFlag: InfoFlag = {
244 | val t = nextToken()
245 | val flag = t match {
246 | case Tokens.Keyword("all-statistics") => AllStatisticsInfoFlag()
247 | case Tokens.Keyword("assertion-stack-levels") => AssertionStackLevelsInfoFlag()
248 | case Tokens.Keyword("authors") => AuthorsInfoFlag()
249 | case Tokens.Keyword("error-behavior") => ErrorBehaviorInfoFlag()
250 | case Tokens.Keyword("name") => NameInfoFlag()
251 | case Tokens.Keyword("reason-unknown") => ReasonUnknownInfoFlag()
252 | case Tokens.Keyword("version") => VersionInfoFlag()
253 | case Tokens.Keyword(keyword) => KeywordInfoFlag(keyword)
254 | case t => expected(t, Tokens.KeywordKind)
255 | }
256 | flag.setPos(t)
257 | }
258 |
259 |
260 | def parseOption: SMTOption = {
261 | val peekPosition = peekToken.getPos
262 | val opt = peekToken match {
263 | case Tokens.Keyword("diagnostic-output-channel") =>
264 | nextToken()
265 | DiagnosticOutputChannel(parseString.value)
266 |
267 | case Tokens.Keyword("global-declarations") =>
268 | nextToken()
269 | GlobalDeclarations(parseBool)
270 |
271 | case Tokens.Keyword("interactive-mode") =>
272 | nextToken()
273 | InteractiveMode(parseBool)
274 | case Tokens.Keyword("print-success") =>
275 | nextToken()
276 | PrintSuccess(parseBool)
277 |
278 | case Tokens.Keyword("produce-assertions") =>
279 | nextToken()
280 | ProduceAssertions(parseBool)
281 | case Tokens.Keyword("produce-assignments") =>
282 | nextToken()
283 | ProduceAssignments(parseBool)
284 | case Tokens.Keyword("produce-models") =>
285 | nextToken()
286 | ProduceModels(parseBool)
287 | case Tokens.Keyword("produce-proofs") =>
288 | nextToken()
289 | ProduceProofs(parseBool)
290 | case Tokens.Keyword("produce-unsat-assumptions") =>
291 | nextToken()
292 | ProduceUnsatAssumptions(parseBool)
293 | case Tokens.Keyword("produce-unsat-cores") =>
294 | nextToken()
295 | ProduceUnsatCores(parseBool)
296 |
297 | case Tokens.Keyword("random-seed") =>
298 | nextToken()
299 | RandomSeed(parseNumeral.value.toInt)
300 |
301 | case Tokens.Keyword("regular-output-channel") =>
302 | nextToken()
303 | RegularOutputChannel(parseString.value)
304 |
305 | case Tokens.Keyword("reproducible-resource-limit") =>
306 | nextToken()
307 | ReproducibleResourceLimit(parseNumeral.value.toInt)
308 | case Tokens.Keyword("verbosity") =>
309 | nextToken()
310 | Verbosity(parseNumeral.value.toInt)
311 |
312 | case _ =>
313 | AttributeOption(parseAttribute)
314 | }
315 | opt.setPos(peekPosition)
316 | }
317 |
318 | def parseBool: Boolean = {
319 | nextToken() match {
320 | case Tokens.SymbolLit("true") => true
321 | case Tokens.SymbolLit("false") => false
322 | case t => expected(t) //TODO: not sure how to tell we were expecting one of two specific symbols
323 | }
324 | }
325 |
326 |
327 | }
328 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/parser/ParserCommandsResponses.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package parser
3 |
4 | import lexer.Tokens
5 | import trees.Terms._
6 | import trees.CommandsResponses._
7 |
8 | import scala.collection.mutable.ListBuffer
9 |
10 | trait ParserCommandsResponses { this: ParserCommon with ParserTerms with ParserCommands =>
11 |
12 | import Parser._
13 |
14 | /*
15 | * Parsing error response, assuming "(" has been parsed
16 | */
17 | private def parseErrorResponse: Error = {
18 | nextToken() match {
19 | case Tokens.SymbolLit("error") =>
20 | val msg = parseString.value
21 | eat(Tokens.CParen)
22 | Error(msg)
23 | case t => expected(t)
24 | }
25 | }
26 |
27 | def parseGenResponse: GenResponse = nextToken() match {
28 | case Tokens.SymbolLit("success") => Success
29 | case Tokens.SymbolLit("unsupported") => Unsupported
30 | case t =>
31 | check(t, Tokens.OParen)
32 | parseErrorResponse
33 | }
34 |
35 | def parseGetAssignmentResponse: GetAssignmentResponse = {
36 | def parsePair: (SSymbol, Boolean) = {
37 | eat(Tokens.OParen)
38 | val sym = parseSymbol
39 | val bool = parseBool
40 | eat(Tokens.CParen)
41 | (sym, bool)
42 | }
43 |
44 | nextToken() match {
45 | case Tokens.SymbolLit("unsupported") => Unsupported
46 | case t => {
47 | check(t, Tokens.OParen)
48 | peekToken match {
49 | case Tokens.SymbolLit("error") => parseErrorResponse
50 | case t => {
51 | val pairs = parseUntil(Tokens.CParen)(() => parsePair)
52 | GetAssignmentResponseSuccess(pairs)
53 | }
54 | }
55 | }
56 | }
57 | }
58 |
59 | def parseGetValueResponse: GetValueResponse = {
60 | def parsePair: (Term, Term) = {
61 | eat(Tokens.OParen)
62 | val t1 = parseTerm
63 | val t2 = parseTerm
64 | eat(Tokens.CParen)
65 | (t1, t2)
66 | }
67 |
68 | nextToken() match {
69 | case Tokens.SymbolLit("unsupported") => Unsupported
70 | case t => {
71 | check(t, Tokens.OParen)
72 | peekToken match {
73 | case Tokens.SymbolLit("error") => parseErrorResponse
74 | case t => {
75 | val pairs = parseUntil(Tokens.CParen)(() => parsePair)
76 | GetValueResponseSuccess(pairs)
77 | }
78 | }
79 | }
80 | }
81 | }
82 |
83 | def parseGetOptionResponse: GetOptionResponse = {
84 | tryParseConstant match {
85 | case Some(cst) => GetOptionResponseSuccess(cst)
86 | case None => {
87 | nextToken() match {
88 | case Tokens.SymbolLit("unsupported") => Unsupported
89 | case Tokens.SymbolLit(sym) => GetOptionResponseSuccess(SSymbol(sym))
90 | case t => {
91 | check(t, Tokens.OParen)
92 | peekToken match {
93 | case Tokens.SymbolLit("error") => parseErrorResponse
94 | case _ => GetOptionResponseSuccess(SList(parseUntil(Tokens.CParen)(() => parseSExpr).toList))
95 | }
96 | }
97 | }
98 | }
99 | }
100 | }
101 |
102 | def parseGetProofResponse: GetProofResponse = {
103 | tryParseConstant match {
104 | case Some(cst) => GetProofResponseSuccess(cst)
105 | case None => {
106 | nextToken() match {
107 | case Tokens.SymbolLit("unsupported") => Unsupported
108 | case Tokens.SymbolLit(sym) => GetProofResponseSuccess(SSymbol(sym))
109 | case Tokens.Keyword(key) => GetProofResponseSuccess(SKeyword(key))
110 | case t => {
111 | check(t, Tokens.OParen)
112 | peekToken match {
113 | case Tokens.SymbolLit("error") => parseErrorResponse
114 | case _ => GetProofResponseSuccess(SList(parseUntil(Tokens.CParen)(() => parseSExpr).toList))
115 | }
116 | }
117 | }
118 | }
119 | }
120 | }
121 |
122 | def parseGetModelResponse: GetModelResponse = {
123 | nextToken() match {
124 | case Tokens.SymbolLit("unsupported") => Unsupported
125 | case t => {
126 | check(t, Tokens.OParen)
127 | peekToken match {
128 | case Tokens.SymbolLit("error") => parseErrorResponse
129 | case t => {
130 | if (peekToken == Tokens.SymbolLit("model")) nextToken()
131 | val exprs: ListBuffer[SExpr] = new ListBuffer
132 | while(peekToken.kind != Tokens.CParen) {
133 | try {
134 | exprs.append(parseCommand)
135 | } catch {
136 | case ex: UnknownCommandException => {
137 | ex.commandName match { //recover for exceptions case in get-model
138 | case Tokens.Forall =>
139 | val vars = parseMany(() => parseSortedVar)
140 | val term = parseTerm
141 | eat(Tokens.CParen)
142 | exprs.append(Forall(vars.head, vars.tail, term))
143 | case _ =>
144 | throw ex
145 | }
146 | }
147 | }
148 | }
149 | eat(Tokens.CParen)
150 | GetModelResponseSuccess(exprs.toList)
151 | }
152 | }
153 | }
154 | }
155 | }
156 |
157 | def parseInfoResponse: InfoResponse = {
158 | peekToken match {
159 | case Tokens.Keyword("assertion-stack-levels") =>
160 | nextToken()
161 | AssertionStackLevelsInfoResponse(parseNumeral.value.toInt)
162 | case Tokens.Keyword("authors") =>
163 | nextToken()
164 | AuthorsInfoResponse(parseString.value)
165 | case Tokens.Keyword("error-behavior") =>
166 | nextToken()
167 | val behaviour = nextToken() match {
168 | case Tokens.SymbolLit("immediate-exit") => ImmediateExitErrorBehavior
169 | case Tokens.SymbolLit("continued-execution") => ContinuedExecutionErrorBehavior
170 | case t => expected(t) //TODO: precise error
171 | }
172 | ErrorBehaviorInfoResponse(behaviour)
173 | case Tokens.Keyword("name") =>
174 | nextToken()
175 | NameInfoResponse(parseString.value)
176 | case Tokens.Keyword("reason-unknown") =>
177 | nextToken()
178 | val reason = nextToken() match {
179 | case Tokens.SymbolLit("timeout") => TimeoutReasonUnknown
180 | case Tokens.SymbolLit("memout") => MemoutReasonUnknown
181 | case Tokens.SymbolLit("incomplete") => IncompleteReasonUnknown
182 | case t => expected(t) //TODO: SMTLIB 2.5 allows arbitrary s-expr
183 | }
184 | ReasonUnknownInfoResponse(reason)
185 | case Tokens.Keyword("version") =>
186 | nextToken()
187 | VersionInfoResponse(parseString.value)
188 | case _ =>
189 | AttributeInfoResponse(parseAttribute)
190 | }
191 | }
192 |
193 | def parseGetInfoResponse: GetInfoResponse = {
194 | nextToken() match {
195 | case Tokens.SymbolLit("unsupported") => Unsupported
196 | case t => {
197 | check(t, Tokens.OParen)
198 | peekToken match {
199 | case Tokens.SymbolLit("error") => parseErrorResponse
200 | case t => {
201 | val responses = parseUntil(Tokens.CParen)(() => parseInfoResponse)
202 | GetInfoResponseSuccess(responses.head, responses.tail)
203 | }
204 | }
205 | }
206 | }
207 | }
208 |
209 | def parseCheckSatResponse: CheckSatResponse = {
210 | nextToken() match {
211 | case Tokens.SymbolLit("sat") => CheckSatStatus(SatStatus)
212 | case Tokens.SymbolLit("unsat") => CheckSatStatus(UnsatStatus)
213 | case Tokens.SymbolLit("unknown") => CheckSatStatus(UnknownStatus)
214 | case Tokens.SymbolLit("unsupported") => Unsupported
215 | case t => {
216 | check(t, Tokens.OParen)
217 | parseErrorResponse
218 | }
219 | }
220 | }
221 |
222 | def parseEchoResponse: EchoResponse = {
223 | nextToken() match {
224 | case Tokens.StringLit(value) => EchoResponseSuccess(value)
225 | case Tokens.SymbolLit("unsupported") => Unsupported
226 | case t => {
227 | check(t, Tokens.OParen)
228 | parseErrorResponse
229 | }
230 | }
231 | }
232 |
233 | def parseGetAssertionsResponse: GetAssertionsResponse = {
234 | nextToken() match {
235 | case Tokens.SymbolLit("unsupported") => Unsupported
236 | case t => {
237 | check(t, Tokens.OParen)
238 | peekToken match {
239 | case Tokens.SymbolLit("error") => parseErrorResponse
240 | case t => {
241 | val terms = parseUntil(Tokens.CParen)(() => parseTerm)
242 | GetAssertionsResponseSuccess(terms)
243 | }
244 | }
245 | }
246 | }
247 | }
248 |
249 | def parseGetUnsatAssumptionsResponse: GetUnsatAssumptionsResponse = {
250 | nextToken() match {
251 | case Tokens.SymbolLit("unsupported") => Unsupported
252 | case t => {
253 | check(t, Tokens.OParen)
254 | peekToken match {
255 | case Tokens.SymbolLit("error") => parseErrorResponse
256 | case t => {
257 | val syms = parseUntil(Tokens.CParen)(() => parseSymbol)
258 | GetUnsatAssumptionsResponseSuccess(syms)
259 | }
260 | }
261 | }
262 | }
263 | }
264 |
265 | def parseGetUnsatCoreResponse: GetUnsatCoreResponse = {
266 | nextToken() match {
267 | case Tokens.SymbolLit("unsupported") => Unsupported
268 | case t => {
269 | check(t, Tokens.OParen)
270 | peekToken match {
271 | case Tokens.SymbolLit("error") => parseErrorResponse
272 | case t => {
273 | val syms = parseUntil(Tokens.CParen)(() => parseSymbol)
274 | GetUnsatCoreResponseSuccess(syms)
275 | }
276 | }
277 | }
278 | }
279 | }
280 | }
281 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/parser/ParserTerms.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package parser
3 |
4 | import lexer.Tokens
5 | import Parser._
6 | import trees.Terms._
7 | import common.Position
8 |
9 | import scala.collection.mutable.ListBuffer
10 |
11 | trait ParserTerms { this: ParserCommon =>
12 |
13 | private def parseQualifiedIdentifier: QualifiedIdentifier = {
14 | getPeekToken.kind match {
15 | case Tokens.OParen => {
16 | val pos = getPeekToken.getPos
17 | eat(Tokens.OParen)
18 | val res = getPeekToken.kind match {
19 | case Tokens.As => {
20 | parseAsIdentifier.setPos(pos)
21 | }
22 | case Tokens.Underscore => {
23 | QualifiedIdentifier(parseUnderscoreIdentifier.setPos(pos)).setPos(pos)
24 | }
25 | case _ => expected(peekToken, Tokens.As, Tokens.Underscore)
26 | }
27 | eat(Tokens.CParen)
28 | res
29 | }
30 | case _ => {
31 | val id = parseIdentifier
32 | QualifiedIdentifier(id).setPos(id)
33 | }
34 | }
35 | }
36 |
37 | protected def parseTermWithoutParens(startPos: Position): Term = getPeekToken.kind match {
38 | case Tokens.Let =>
39 | eat(Tokens.Let)
40 | val (head, bindings) = parseOneOrMore(() => parseVarBinding)
41 | val term = parseTerm
42 | Let(head, bindings, term)
43 |
44 | case Tokens.Forall =>
45 | eat(Tokens.Forall)
46 | val (head, vars) = parseOneOrMore(() => parseSortedVar)
47 | val term = parseTerm
48 | Forall(head, vars, term)
49 |
50 | case Tokens.Exists =>
51 | eat(Tokens.Exists)
52 | val (head, vars) = parseOneOrMore(() => parseSortedVar)
53 | val term = parseTerm
54 | Exists(head, vars, term)
55 |
56 | case Tokens.ExclamationMark =>
57 | eat(Tokens.ExclamationMark)
58 | val term = parseTerm
59 | val head = parseAttribute
60 | val attrs = parseUntil(Tokens.CParen, eatEnd = false)(() => parseAttribute)
61 | AnnotatedTerm(term, head, attrs)
62 |
63 | case Tokens.As =>
64 | parseAsIdentifier
65 |
66 | case Tokens.Underscore =>
67 | QualifiedIdentifier(parseUnderscoreIdentifier.setPos(startPos)).setPos(startPos)
68 |
69 | case _ => //should be function application
70 | val id = parseQualifiedIdentifier
71 | val head = parseTerm
72 | val terms = parseUntil(Tokens.CParen, eatEnd = false)(() => parseTerm)
73 | FunctionApplication(id, head::terms.toList)
74 | }
75 |
76 | def parseTerm: Term = {
77 | if(getPeekToken.kind == Tokens.OParen) {
78 | val startPos = getPeekToken.getPos
79 | val t = parseWithin(Tokens.OParen, Tokens.CParen)(() => parseTermWithoutParens(startPos))
80 | t.setPos(startPos)
81 | } else {
82 | val cst = tryParseConstant
83 | cst.getOrElse({
84 | val id = parseIdentifier
85 | QualifiedIdentifier(id).setPos(id)
86 | })
87 | }
88 | }
89 |
90 |
91 | def tryParseConstant: Option[Constant] = {
92 | getPeekToken.kind match {
93 | case Tokens.NumeralLitKind => Some(parseNumeral)
94 | case Tokens.HexadecimalLitKind => Some(parseHexadecimal)
95 | case Tokens.BinaryLitKind => Some(parseBinary)
96 | case Tokens.DecimalLitKind => Some(parseDecimal)
97 | case Tokens.StringLitKind => Some(parseString)
98 | case _ => None
99 | }
100 | }
101 |
102 |
103 | def parseVarBinding: VarBinding = {
104 | val start = eat(Tokens.OParen)
105 | val sym = parseSymbol
106 | val term = parseTerm
107 | eat(Tokens.CParen)
108 | VarBinding(sym, term).setPos(start)
109 | }
110 | def parseSortedVar: SortedVar = {
111 | val start = eat(Tokens.OParen)
112 | val sym = parseSymbol
113 | val sort = parseSort
114 | eat(Tokens.CParen)
115 | SortedVar(sym, sort).setPos(start)
116 | }
117 |
118 | }
119 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/printer/Printer.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package printer
3 |
4 | import trees.Commands._
5 | import trees.CommandsResponses._
6 | import trees.Terms._
7 | import trees.Tree
8 |
9 | import java.io.Writer
10 | import java.io.StringWriter
11 | import java.io.BufferedWriter
12 |
13 | trait Printer {
14 |
15 | val name: String
16 |
17 | protected def newContext(writer: Writer): PrintingContext
18 |
19 | private def print(tree: Tree, writer: Writer): Unit = newContext(writer).output(tree)
20 |
21 | def printTerm(term: Term, writer: Writer): Unit = print(term, writer)
22 | def printSort(sort: Sort, writer: Writer): Unit = print(sort, writer)
23 | def printCommand(cmd: Command, writer: Writer): Unit = print(cmd, writer)
24 | def printCommandResponse(resp: CommandResponse, writer: Writer): Unit = print(resp, writer)
25 | def printSExpr(sexpr: SExpr, writer: Writer): Unit = print(sexpr, writer)
26 |
27 | def printScript(script: Script, writer: Writer): Unit = {
28 | for (cmd <- script.commands) printCommand(cmd, writer)
29 | }
30 |
31 | private def treeToString(tree: Tree): String = {
32 | val output = new StringWriter
33 | val writer = new BufferedWriter(output)
34 | print(tree, writer)
35 | writer.flush()
36 | output.toString
37 | }
38 |
39 | def toString(term: Term): String = treeToString(term)
40 | def toString(sort: Sort): String = treeToString(sort)
41 | def toString(command: Command): String = treeToString(command)
42 | def toString(response: CommandResponse): String = treeToString(response)
43 | def toString(sexpr: SExpr): String = treeToString(sexpr)
44 |
45 | def toString(script: Script): String = {
46 | val output = new StringWriter
47 | val writer = new BufferedWriter(output)
48 | for (cmd <- script.commands) printCommand(cmd, writer)
49 | writer.flush()
50 | output.toString
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/printer/RecursivePrinter.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package printer
3 |
4 | import trees.Commands._
5 | import trees.CommandsResponses._
6 | import trees.Terms._
7 | import trees.Tree
8 |
9 | import java.io.Writer
10 |
11 | object RecursivePrinter extends Printer {
12 |
13 | override val name: String = "recursive-printer"
14 |
15 | override protected def newContext(writer: Writer): PrintingContext = new PrintingContext(writer)
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/printer/TailPrinter.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package printer
3 |
4 | import common.LinkedList
5 |
6 | import trees.Commands._
7 | import trees.CommandsResponses._
8 | import trees.Terms._
9 | import trees.Tree
10 |
11 | import java.io.Writer
12 |
13 | import scala.collection.mutable.Stack
14 |
15 | object TailPrinter extends Printer {
16 |
17 | override val name: String = "tail-printer"
18 |
19 | override protected def newContext(writer: Writer) = new TailContext(writer)
20 | }
21 |
22 | class TailContext(writer: Writer) extends PrintingContext(writer) {
23 | var actions = new LinkedList[() => Unit]
24 | var actionStack = List[LinkedList[() => Unit]]()
25 |
26 | override def print(tree: Tree): Unit = {
27 | actions.append(() => super.print(tree))
28 | }
29 |
30 | override def print(str: String): Unit = {
31 | actions.append(() => super.print(str))
32 | }
33 |
34 | override protected def finish(): Unit = {
35 | while (!actions.isEmpty || !actionStack.isEmpty) {
36 | if (actions.isEmpty) {
37 | actions = actionStack.head
38 | actionStack = actionStack.tail
39 | } else {
40 | val action = actions.pop()
41 | actionStack ::= actions
42 | actions = new LinkedList[() => Unit]
43 | action()
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/theories/ArraysEx.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package theories
3 |
4 | import trees.Terms._
5 |
6 | import Operations._
7 |
8 | object ArraysEx {
9 |
10 | object ArraySort {
11 | def apply(from: Sort, to: Sort): Sort = Sort(Identifier(SSymbol("Array")), Seq(from, to))
12 | def unapply(sort: Sort): Option[(Sort, Sort)] = sort match {
13 | case Sort(Identifier(SSymbol("Array"), Seq()), Seq(from, to)) => Some((from, to))
14 | case _ => None
15 | }
16 | }
17 |
18 | object Select extends Operation2 { override val name = "select" }
19 | object Store extends Operation3 { override val name = "store" }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/theories/Constructors.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package theories
3 |
4 | import trees.Terms._
5 | import Core._
6 | import Ints._
7 |
8 | /** Provide builders functions for all theories, which perform simplifications.
9 | *
10 | * We use the convention that capital letter operations (apply) do not perform
11 | * any syntactic simplification and build exactly the tree corresponding to
12 | * its definition, while corresponding functions with lower case letter can
13 | * potentially return a different representation than what it is called with.
14 | *
15 | * An example is the `And` vs `and` operation. The `And` needs a minimum of two
16 | * arguments, and will always produce a function application (and e1 e2 ...) with
17 | * the exact same element as provided. But the `and` constructor is more flexible
18 | * and will accept 0, 1 or more arguments, and will perform many simplifications. If
19 | * called with 0 argument, it would return `true`, while if called with 1 it would return
20 | * the element itself. Notice how in both case, even though you call the `and` constructor
21 | * you don't get an `and` in the resulting expression. Similarly, an `and` with many
22 | * arguments might simplify away `true` literals, or reduce the whole expression to
23 | * `false` if one element is `false`. The `And` apply method will always keep literals
24 | * without simplifying them away.
25 | *
26 | * So why not always use simplifying methods? First, they are slightly more expensive
27 | * than the corresponding capital letter constructors, as they will inspect the
28 | * expressions and do some processing on them. Second, there are times where you might
29 | * want precise control over the syntax, and having syntax-only methods as primitive
30 | * is very useful. One main difference is that those constructors perform some semantics
31 | * transformations, while capital letter constructors are purely syntactic.
32 | *
33 | * Finally note that one cannot assume anything more than semantics equivalence for the
34 | * returned term. The constructor is free to perform any sort of rewriting, so even
35 | * if you expect that calling and(true, false, x) should return false, it might still
36 | * return something like and(false, x). However, it will only return syntactically
37 | * correct term, so you would not get And(false). Usually, the above expression will
38 | * correctly get simplified to false, but the general way of thinking about these
39 | * constructors is as a best-effort simplification: it will do some relatively easy
40 | * and cheap simplification, but the exact contract does not specify the level of
41 | * simplification. This limitation is there as, in general, it is impossible to
42 | * properly specify the "correct" simplified form for a given formula.
43 | */
44 | object Constructors {
45 |
46 | /*
47 | * We decide to not provide a varargs version that takes only 0 or 1 argument. The
48 | * reason is that we cannot forsee a use-case where a programmer would want to call
49 | * `and` with a statically known amount of argument 0 or 1, it would rather use the
50 | * corresponding simplified expression which is `true` or the single argument itself.
51 | *
52 | * However, cases with 0 or 1 argument could happen when and takes a Seq, as it is
53 | * possible that a program might just want to conjunct a dynamically sized list
54 | */
55 | def and(t1: Term, t2: Term, ts: Term*): Term = and(t1 +: t2 +: ts)
56 | def and(ts: Seq[Term]): Term = {
57 | val flat = ts.flatMap{
58 | case And(es@_*) => es
59 | case o => Seq(o)
60 | }
61 |
62 | var isFalse = false
63 | val simpler = ts.filter{
64 | case False() =>
65 | isFalse = true
66 | false
67 | case True() => false
68 | case _ => true
69 | }
70 |
71 | if(isFalse) False() else simpler match {
72 | case Seq() => True()
73 | case Seq(t) => t
74 | case _ => And(ts)
75 | }
76 | }
77 |
78 | def or(t1: Term, t2: Term, ts: Term*): Term = or(t1 +: t2 +: ts)
79 | def or(ts: Seq[Term]): Term = {
80 | val flat = ts.flatMap{
81 | case Or(es@_*) => es
82 | case o => Seq(o)
83 | }
84 |
85 | var isTrue = false
86 | val simpler = ts.filter{
87 | case True() =>
88 | isTrue = true
89 | false
90 | case False() => false
91 | case _ => true
92 | }
93 |
94 | if(isTrue) True() else simpler match {
95 | case Seq() => False()
96 | case Seq(t) => t
97 | case _ => Or(ts)
98 | }
99 | }
100 |
101 | def not(t: Term): Term = t match {
102 | case True() => False()
103 | case False() => True()
104 |
105 | case Not(s) => s
106 | case And(ts@_*) => or(ts map not)
107 | case Or(ts@_*) => and(ts map not)
108 | case Implies(t1, t2) => and(t1, not(t2))
109 |
110 | case LessThan(t1, t2) => GreaterEquals(t1, t2)
111 | case LessEquals(t1, t2) => GreaterThan(t1, t2)
112 | case GreaterThan(t1, t2) => LessEquals(t1, t2)
113 | case GreaterEquals(t1, t2) => LessThan(t1, t2)
114 |
115 | case _ => Not(t)
116 | }
117 |
118 | }
119 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/theories/Core.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package theories
3 |
4 | import trees.Terms._
5 |
6 | import Operations._
7 |
8 | object Core {
9 |
10 | object BoolSort {
11 | def apply(): Sort = Sort(Identifier(SSymbol("Bool")))
12 | def unapply(sort: Sort): Boolean = sort match {
13 | case Sort(Identifier(SSymbol("Bool"), Seq()), Seq()) => true
14 | case _ => false
15 | }
16 | }
17 |
18 | object BoolConst {
19 | def apply(v: Boolean): Term = if(v) True() else False()
20 | }
21 |
22 | object True extends Operation0 { override val name = "true" }
23 | object False extends Operation0 { override val name = "false" }
24 |
25 | object Not extends Operation1 { override val name = "not" }
26 | object Implies extends Operation2 { override val name = "=>" }
27 | object And extends OperationN2 { override val name = "and" }
28 | object Or extends OperationN2 { override val name = "or" }
29 | object Xor extends Operation2 { override val name = "xor" }
30 |
31 | object Equals extends Operation2 { override val name = "=" }
32 |
33 | object ITE extends Operation3 { override val name = "ite" }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/theories/FixedSizeBitVectors.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package theories
3 |
4 | import trees.Terms._
5 | import common._
6 |
7 | import Operations._
8 |
9 | object FixedSizeBitVectors {
10 |
11 | object BitVectorSort {
12 | def apply(length: BigInt): Sort = {
13 | require(length > 0)
14 | Sort(Identifier(SSymbol("BitVec"), Seq(SNumeral(length))))
15 | }
16 | def unapply(sort: Sort): Option[BigInt] = sort match {
17 | case Sort(Identifier(SSymbol("BitVec"), Seq(SNumeral(n))), Seq()) if n > 0 => Some(n)
18 | case _ => None
19 | }
20 | }
21 |
22 | object BitVectorLit {
23 | def apply(content: List[Boolean]): Term = SBinary(content)
24 |
25 | /** Construct a bit-vector literal from an hexadecimal
26 | *
27 | * The bitvector theory interprets the hexadecimal literals
28 | * as a bit vector of size 4 times the length of the hexadecimal
29 | * representation
30 | */
31 | def apply(content: Hexadecimal): Term = SHexadecimal(content)
32 |
33 | def unapply(term: Term): Option[List[Boolean]] = term match {
34 | case SBinary(content) => Some(content)
35 | case SHexadecimal(hexa) => Some(hexa.toBinary)
36 | case _ => None
37 | }
38 | }
39 |
40 | /**
41 | * shorthand notation (_ bv13 32) for the number 13 with 32 bits
42 | */
43 | object BitVectorConstant {
44 | def apply(x: BigInt, n: BigInt): Term =
45 | QualifiedIdentifier(Identifier(SSymbol("bv" + x), Seq(SNumeral(n))))
46 | //TODO: BigInt is not the best data representation for a bitvector, we should probably use a list of boolean kind of representation
47 | def unapply(term: Term): Option[(BigInt, BigInt)] = term match {
48 | case QualifiedIdentifier(
49 | Identifier(SSymbol(cst), Seq(SNumeral(size))),
50 | None
51 | ) if cst startsWith "bv" =>
52 | Some(BigInt(cst drop 2) -> size)
53 |
54 | case _ => None
55 | }
56 | }
57 |
58 |
59 | object Concat extends Operation2 { override val name = "concat" }
60 |
61 | object Not extends Operation1 { override val name = "bvnot" }
62 | object Neg extends Operation1 { override val name = "bvneg" }
63 | object And extends Operation2 { override val name = "bvand" }
64 | object Or extends Operation2 { override val name = "bvor" }
65 | object NAnd extends Operation2 { override val name = "bvnand" }
66 | object NOr extends Operation2 { override val name = "bvnor" }
67 | object XOr extends Operation2 { override val name = "bvxor" }
68 | object XNOr extends Operation2 { override val name = "bvxnor" }
69 |
70 | object Comp extends Operation2 { override val name = "bvcomp" }
71 | object Add extends Operation2 { override val name = "bvadd" }
72 | object Sub extends Operation2 { override val name = "bvsub" }
73 | object Mul extends Operation2 { override val name = "bvmul" }
74 | object UDiv extends Operation2 { override val name = "bvudiv" }
75 | object SDiv extends Operation2 { override val name = "bvsdiv" }
76 | object URem extends Operation2 { override val name = "bvurem" }
77 | object SRem extends Operation2 { override val name = "bvsrem" }
78 | object SMod extends Operation2 { override val name = "bvsmod" }
79 |
80 | object ULessThan extends Operation2 { override val name = "bvult" }
81 | object ULessEquals extends Operation2 { override val name = "bvule" }
82 | object UGreaterThan extends Operation2 { override val name = "bvugt" }
83 | object UGreaterEquals extends Operation2 { override val name = "bvuge" }
84 | object SLessThan extends Operation2 { override val name = "bvslt" }
85 | object SLessEquals extends Operation2 { override val name = "bvsle" }
86 | object SGreaterThan extends Operation2 { override val name = "bvsgt" }
87 | object SGreaterEquals extends Operation2 { override val name = "bvsge" }
88 |
89 | object ShiftLeft extends Operation2 { override val name = "bvshl" }
90 | object LShiftRight extends Operation2 { override val name = "bvlshr" }
91 | object AShiftRight extends Operation2 { override val name = "bvashr" }
92 |
93 |
94 | object Extract {
95 | def apply(i: BigInt, j: BigInt, t: Term): Term =
96 | FunctionApplication(
97 | QualifiedIdentifier(Identifier(SSymbol("extract"), Seq(SNumeral(i), SNumeral(j)))),
98 | Seq(t)
99 | )
100 | def unapply(term: Term): Option[(BigInt, BigInt, Term)] = term match {
101 | case FunctionApplication(
102 | QualifiedIdentifier(
103 | Identifier(SSymbol("extract"), Seq(SNumeral(i), SNumeral(j))),
104 | None
105 | ), Seq(t)) => Some((i, j, t))
106 | case _ => None
107 | }
108 | }
109 |
110 | object Repeat {
111 | def apply(i: BigInt, t: Term): Term = {
112 | require(i >= 1)
113 | FunctionApplication(
114 | QualifiedIdentifier(Identifier(SSymbol("repeat"), Seq(SNumeral(i)))),
115 | Seq(t)
116 | )
117 | }
118 | def unapply(term: Term): Option[(BigInt, Term)] = term match {
119 | case FunctionApplication(
120 | QualifiedIdentifier(
121 | Identifier(SSymbol("repeat"), Seq(SNumeral(i))),
122 | None
123 | ), Seq(t)) => Some((i, t))
124 | case _ => None
125 | }
126 | }
127 |
128 | object ZeroExtend {
129 | def apply(i: BigInt, t: Term): Term = {
130 | require(i >= 0)
131 | FunctionApplication(
132 | QualifiedIdentifier(Identifier(SSymbol("zero_extend"), Seq(SNumeral(i)))),
133 | Seq(t)
134 | )
135 | }
136 | def unapply(term: Term): Option[(BigInt, Term)] = term match {
137 | case FunctionApplication(
138 | QualifiedIdentifier(
139 | Identifier(SSymbol("zero_extend"), Seq(SNumeral(i))),
140 | None
141 | ), Seq(t)) => Some((i, t))
142 | case _ => None
143 | }
144 | }
145 |
146 | object SignExtend {
147 | def apply(i: BigInt, t: Term): Term = {
148 | require(i >= 0)
149 | FunctionApplication(
150 | QualifiedIdentifier(Identifier(SSymbol("sign_extend"), Seq(SNumeral(i)))),
151 | Seq(t)
152 | )
153 | }
154 | def unapply(term: Term): Option[(BigInt, Term)] = term match {
155 | case FunctionApplication(
156 | QualifiedIdentifier(
157 | Identifier(SSymbol("sign_extend"), Seq(SNumeral(i))),
158 | None
159 | ), Seq(t)) => Some((i, t))
160 | case _ => None
161 | }
162 | }
163 |
164 | object RotateLeft {
165 | def apply(i: BigInt, t: Term): Term = {
166 | require(i >= 0)
167 | FunctionApplication(
168 | QualifiedIdentifier(Identifier(SSymbol("rotate_left"), Seq(SNumeral(i)))),
169 | Seq(t)
170 | )
171 | }
172 | def unapply(term: Term): Option[(BigInt, Term)] = term match {
173 | case FunctionApplication(
174 | QualifiedIdentifier(
175 | Identifier(SSymbol("rotate_left"), Seq(SNumeral(i))),
176 | None
177 | ), Seq(t)) => Some((i, t))
178 | case _ => None
179 | }
180 | }
181 |
182 | object RotateRight {
183 | def apply(i: BigInt, t: Term): Term = {
184 | require(i >= 0)
185 | FunctionApplication(
186 | QualifiedIdentifier(Identifier(SSymbol("rotate_right"), Seq(SNumeral(i)))),
187 | Seq(t)
188 | )
189 | }
190 | def unapply(term: Term): Option[(BigInt, Term)] = term match {
191 | case FunctionApplication(
192 | QualifiedIdentifier(
193 | Identifier(SSymbol("rotate_right"), Seq(SNumeral(i))),
194 | None
195 | ), Seq(t)) => Some((i, t))
196 | case _ => None
197 | }
198 | }
199 |
200 | }
201 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/theories/Ints.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package theories
3 |
4 | import trees.Terms._
5 |
6 | import Operations._
7 |
8 | object Ints {
9 |
10 | object IntSort {
11 | def apply(): Sort = {
12 | Sort(Identifier(SSymbol("Int")))
13 | }
14 | def unapply(sort: Sort): Boolean = sort match {
15 | case Sort(Identifier(SSymbol("Int"), Seq()), Seq()) => true
16 | case _ => false
17 | }
18 | }
19 |
20 | object NumeralLit {
21 | def apply(value: BigInt): Term = SNumeral(value)
22 | def unapply(term: Term): Option[BigInt] = term match {
23 | case SNumeral(value) => Some(value)
24 | case _ => None
25 | }
26 | }
27 |
28 | object Divisible {
29 | def apply(n: BigInt, t: Term): Term =
30 | FunctionApplication(
31 | QualifiedIdentifier(Identifier(SSymbol("divisible"), Seq(SNumeral(n)))),
32 | Seq(t)
33 | )
34 | def unapply(term: Term): Option[(BigInt, Term)] = term match {
35 | case FunctionApplication(
36 | QualifiedIdentifier(
37 | Identifier(SSymbol("divisible"), Seq(SNumeral(n))),
38 | None
39 | ), Seq(t)) => Some((n, t))
40 | case _ => None
41 | }
42 | }
43 |
44 | object Neg extends Operation1 { override val name = "-" }
45 | object Add extends Operation2 { override val name = "+" }
46 | object Sub extends Operation2 { override val name = "-" }
47 | object Mul extends Operation2 { override val name = "*" }
48 | object Div extends Operation2 { override val name = "div" }
49 | object Mod extends Operation2 { override val name = "mod" }
50 | object Abs extends Operation1 { override val name = "abs" }
51 |
52 | object LessThan extends Operation2 { override val name = "<" }
53 | object LessEquals extends Operation2 { override val name = "<=" }
54 | object GreaterThan extends Operation2 { override val name = ">" }
55 | object GreaterEquals extends Operation2 { override val name = ">=" }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/theories/Operations.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package theories
3 |
4 | import trees.Terms._
5 |
6 | /** General patterns for building and extracting FunctionApplication in theories.
7 | *
8 | * Most SMT-LIB theories are a definition of many built-in functions. We do not
9 | * wish to extend the core abstract syntax tree of SMT-LIB with theory specific
10 | * operations, so a theory definition is simply providing Constructors and Extractors
11 | * to build the proper trees out of core SMT-LIB FunctionApplication and Identifier.
12 | *
13 | * this object provides traits to facilitate the definition of custom
14 | * FunctionApplication with apply and unapply methods. They provide the proper
15 | * signatures for different arities.
16 | *
17 | * Refer to any theory definition to see examples of how to use these traits.
18 | */
19 | object Operations {
20 |
21 | /**
22 | * Operations with no arguments
23 | */
24 | trait Operation0 {
25 | val name: String
26 |
27 | def apply(): Term = QualifiedIdentifier(Identifier(SSymbol(name)))
28 |
29 | def unapply(t : Term): Boolean = t match {
30 | case QualifiedIdentifier(Identifier(SSymbol(`name`), Seq()), None) => true
31 | case _ => false
32 | }
33 | }
34 |
35 | /**
36 | * Operations with exactly one argument
37 | */
38 | trait Operation1 {
39 | val name: String
40 |
41 | def apply(i : Term): Term =
42 | FunctionApplication(QualifiedIdentifier(Identifier(SSymbol(name))),
43 | Seq(i))
44 |
45 | def unapply(t : Term): Option[Term] = t match {
46 | case FunctionApplication(
47 | QualifiedIdentifier(Identifier(SSymbol(`name`), Seq()), None),
48 | Seq(i)) => Some(i)
49 | case _ => None
50 | }
51 | }
52 |
53 | /**
54 | * Operations with exactly two argument
55 | */
56 | trait Operation2 {
57 | val name: String
58 |
59 | def apply(l : Term, r : Term): Term =
60 | FunctionApplication(QualifiedIdentifier(Identifier(SSymbol(name))),
61 | Seq(l,r))
62 |
63 | def unapply(t : Term): Option[(Term, Term)] = t match {
64 | case FunctionApplication(
65 | QualifiedIdentifier(Identifier(SSymbol(`name`), Seq()), None),
66 | Seq(l,r)) => Some((l,r))
67 | case _ => None
68 | }
69 | }
70 |
71 | /**
72 | * Operations with exactly three argument
73 | */
74 | trait Operation3 {
75 | val name: String
76 |
77 | def apply(l : Term, m : Term, r : Term): Term =
78 | FunctionApplication(QualifiedIdentifier(Identifier(SSymbol(name))),
79 | Seq(l,m,r))
80 |
81 | def unapply(t : Term): Option[(Term, Term, Term)] = t match {
82 | case FunctionApplication(
83 | QualifiedIdentifier(Identifier(SSymbol(`name`), Seq()), None),
84 | Seq(l,m,r)) => Some((l,m,r))
85 | case _ => None
86 | }
87 | }
88 |
89 | /**
90 | * Operations with variable number of arguments, requiring that the number of arguments is greater than least `numRequired`
91 | */
92 | trait OperationN {
93 | val name: String
94 |
95 | val numRequired: Int
96 |
97 | def apply(is: Seq[Term]): Term = {
98 | require(is.size >= numRequired)
99 | FunctionApplication(QualifiedIdentifier(Identifier(SSymbol(name))), is)
100 | }
101 |
102 | //TODO: not sure which unapply is better to provide
103 | //def unapply(t : Term): Option[Seq[Term]] = t match {
104 | // case FunctionApplication(
105 | // QualifiedIdentifier(Identifier(SSymbol(`name`), Seq()), None),
106 | // is) if is.size >= numRequired => Some(is)
107 | // case _ => None
108 | //}
109 |
110 | def unapplySeq(term: Term): Option[Seq[Term]] = term match {
111 | case FunctionApplication(
112 | QualifiedIdentifier(
113 | Identifier(SSymbol(`name`), Seq()),
114 | None
115 | ), seqTerm) if seqTerm.length >= 2 => Some(seqTerm)
116 | case _ => None
117 | }
118 |
119 | }
120 |
121 | /**
122 | * Operations with variable number of arguments, none required
123 | */
124 | trait OperationN0 extends OperationN {
125 | override val numRequired: Int = 0
126 | }
127 |
128 | /**
129 | * Operations with variable number of arguments, at least one required
130 | */
131 | trait OperationN1 extends OperationN {
132 | override val numRequired: Int = 1
133 |
134 | def apply(i1: Term, is: Term*): Term = apply(i1 +: is)
135 | }
136 |
137 | /** Operations with variable number of arguments, at least two required
138 | *
139 | * Corresponds to the many operations that are defined for two arguments and
140 | * marked as :left-assoc or :pairwise (such as `and` or `distinct`). Note that
141 | * the resulting representation in terms of AST will be the n-ary function application,
142 | * and not the desugared version (successive binary operation). This choice seems to
143 | * make sense for operations such as distinct that would require an exponential
144 | * blowup to desugar the expression, while the latest phase of the solvers might
145 | * be able to do something smarter with the more concise operation.
146 | */
147 | trait OperationN2 extends OperationN {
148 | override val numRequired: Int = 2
149 |
150 | def apply(i1: Term, i2: Term, is: Term*): Term = apply(i1 +: i2 +: is)
151 |
152 | }
153 |
154 | /**
155 | * Operations with variable number of arguments, at least three required
156 | */
157 | trait OperationN3 extends OperationN {
158 | override val numRequired: Int = 3
159 |
160 | def apply(i1: Term, i2: Term, i3: Term, is: Term*): Term = apply(i1 +: i2 +: i3 +: is)
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/theories/Reals.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package theories
3 |
4 | import trees.Terms._
5 |
6 | import Operations._
7 |
8 | object Reals {
9 |
10 | /*
11 | * TODO: how about providing a Rational constructor? maybe it should go in Constructors?
12 | */
13 |
14 | object RealSort {
15 | def apply(): Sort = {
16 | Sort(Identifier(SSymbol("Real")))
17 | }
18 | def unapply(sort: Sort): Boolean = sort match {
19 | case Sort(Identifier(SSymbol("Real"), Seq()), Seq()) => true
20 | case _ => false
21 | }
22 | }
23 |
24 | object NumeralLit {
25 | def apply(value: BigInt): Term = SNumeral(value)
26 | def unapply(term: Term): Option[BigInt] = term match {
27 | case SNumeral(value) => Some(value)
28 | case _ => None
29 | }
30 | }
31 |
32 | object DecimalLit {
33 | def apply(value: BigDecimal): Term = SDecimal(value)
34 | def unapply(term: Term): Option[BigDecimal] = term match {
35 | case SDecimal(value) => Some(value)
36 | case _ => None
37 | }
38 | }
39 |
40 | object Neg extends Operation1 { override val name = "-" }
41 | object Add extends Operation2 { override val name = "+" }
42 | object Sub extends Operation2 { override val name = "-" }
43 | object Mul extends Operation2 { override val name = "*" }
44 | object Div extends Operation2 { override val name = "/" }
45 |
46 | object LessThan extends Operation2 { override val name = "<" }
47 | object LessEquals extends Operation2 { override val name = "<=" }
48 | object GreaterThan extends Operation2 { override val name = ">" }
49 | object GreaterEquals extends Operation2 { override val name = ">=" }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/theories/experimental/Sets.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package theories
3 | package experimental
4 |
5 | import trees.Terms._
6 | import Operations._
7 |
8 | /* Experimental support for the theory of sets in CVC4
9 | * Based on the operations in http://cvc4.cs.nyu.edu/wiki/Sets
10 | */
11 | object Sets {
12 |
13 | private val SetUnion: String = "union"
14 | private val SetIntersection: String = "intersection"
15 | private val SetMinus: String = "setminus"
16 | private val SetMember: String = "member"
17 | private val SetSubset: String = "subset"
18 | private val SetEmptyset: String = "emptyset"
19 | private val SetSingleton: String = "singleton"
20 | private val SetInsert: String = "insert"
21 | private val SetCard: String = "card"
22 |
23 | object SetSort {
24 | def apply(el : Sort): Sort = Sort(Identifier(SSymbol("Set")), Seq(el))
25 |
26 | def unapply(sort : Sort): Option[Sort] = sort match {
27 | case Sort(Identifier(SSymbol("Set"), Seq()), Seq(el)) => Some(el)
28 | case _ => None
29 | }
30 | }
31 |
32 | object Union extends Operation2 { override val name = SetUnion }
33 | object Intersection extends Operation2 { override val name = SetIntersection }
34 | object Setminus extends Operation2 { override val name = SetMinus }
35 | object Member extends Operation2 { override val name = SetMember }
36 | object Subset extends Operation2 { override val name = SetSubset }
37 |
38 | object EmptySet {
39 | def apply(s : Sort): Term = QualifiedIdentifier(Identifier(SSymbol(SetEmptyset)), Some(s))
40 | def unapply(t : Term): Option[Sort] = t match {
41 | case QualifiedIdentifier(Identifier(SSymbol(SetEmptyset), Seq()), Some(s)) =>
42 | Some(s)
43 | case _ => None
44 | }
45 | }
46 |
47 | object Singleton extends Operation1 { override val name = SetSingleton }
48 |
49 | object Insert extends OperationN2 { override val name = SetInsert }
50 |
51 | object Card extends Operation1 { override val name = SetCard }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/theories/experimental/Strings.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package theories
3 | package experimental
4 |
5 | import trees.Terms._
6 | import Operations._
7 |
8 | object Strings {
9 |
10 | /** The strings and format are taken from here:
11 | * http://cvc4.cs.nyu.edu/wiki/Strings#Examples
12 | */
13 |
14 | private val StringConcat = "str.++"
15 | private val StringLength = "str.len"
16 | private val StringAt = "str.at"
17 | private val StringSubstring = "str.substr"
18 | private val StringInRegex = "str.in.re"
19 | private val StringToRegex = "str.to.re"
20 |
21 | private val StringContains = "str.contains"
22 | private val StringIndexOf = "str.indexof"
23 | private val StringReplace = "str.replace"
24 | private val StringPrefixOf = "str.prefixof"
25 | private val StringSuffixOf = "str.suffixof"
26 | private val StringStringToInt = "str.to.int"
27 | private val StringIntToString = "int.to.str"
28 |
29 | private val RegexConcat = "re.++"
30 | private val RegexUnion = "re.union"
31 | private val RegexInter = "re.inter"
32 | private val RegexKleeneStar = "re.*"
33 | private val RegexKleeneCross = "re.+"
34 | private val RegexKleeneOpt = "re.opt"
35 | private val RegexRange = "re.range"
36 | private val RegexLoop = "re.loop"
37 | private val RegexLoop2 = "re.loop2"
38 | private val RegexEmpty = "re.nostr"
39 | private val RegexAllChar = "re.allchar"
40 |
41 |
42 | object StringSort {
43 | def apply(): Sort = {
44 | Sort(Identifier(SSymbol("String")))
45 | }
46 | def unapply(sort: Sort): Boolean = sort match {
47 | case Sort(Identifier(SSymbol("String"), Seq()), Seq()) => true
48 | case _ => false
49 | }
50 | }
51 |
52 | object StringLit {
53 | def apply(value: String): Term = SString(value)
54 | def unapply(term: Term): Option[String] = term match {
55 | case SString(value) => Some(value)
56 | case _ => None
57 | }
58 | }
59 |
60 | /** Length of string. */
61 | object Length extends Operation1 { override val name = StringLength }
62 |
63 | /** String concatenation takes at least 2 arguments. */
64 | object Concat extends OperationN2 { override val name = StringConcat }
65 |
66 | /** Character in String. First argument is a string term and second is a natural number. The index is starting from 0. */
67 | object At extends Operation2 { override val name = StringAt }
68 |
69 | /** Substring given string, start and length/offset */
70 | object Substring extends Operation3 { override val name = StringSubstring }
71 |
72 | /** Membership Constraint where first arg is a string term and second a regular expression. */
73 | object InRegex extends Operation2 { override val name = StringInRegex }
74 |
75 | /** String to Regular Expression Conversion.
76 | * The statement turns a regular expression that only contains a string s.
77 | */
78 | object ToRegex extends Operation1 { override val name = StringToRegex }
79 |
80 | object Regex {
81 | /** Membership constraint. See [InRegex]. */
82 | val In = InRegex
83 | /** Membership constraint. See [ToRegex]. */
84 | val To = ToRegex
85 |
86 | lazy val Star = KleeneStar
87 | lazy val * = KleeneStar
88 | lazy val Cross = KleeneCross
89 | lazy val Plus = KleeneCross
90 | lazy val + = KleeneCross
91 | lazy val ? = Opt
92 | lazy val NoStr = Empty
93 |
94 | /** Regular Expression Concatenation. */
95 | object Concat extends OperationN2 { override val name = RegexConcat }
96 | /** Regular Expression Alternation. */
97 | object Union extends OperationN2 { override val name = RegexUnion }
98 | /** Regular Expression Intersection. */
99 | object Inter extends OperationN2 { override val name = RegexInter }
100 | /** Regular Expression Kleene-Star (equivalent to Loop(r, 0)) */
101 | object KleeneStar extends Operation1 { override val name = RegexKleeneStar }
102 | /** Regular Expression Kleene-Cross (equivalent to Loop(r, 1)) */
103 | object KleeneCross extends Operation1 { override val name = RegexKleeneCross }
104 | /** Regular Expression Option marker (equivalent to Loop(r, 0, 1)) */
105 | object Opt extends Operation1 { override val name = RegexKleeneOpt }
106 | /** Regular Expression Range where arguments s, t are single characters in double quotes, e.g. "a", "b". It returns a regular expression that contains any character between s and t.*/
107 | object Range extends Operation2 { override val name = RegexRange }
108 |
109 | /** Regular Expression Loop with arguments (r, l, u) where r is a regular expression, l is a non-negative constant integer, and u is an optional non-negative constant integer. It returns a regular expression that contains at least l repetitions of r and at most u repetitions of r. If l >= u, it returns exactly l repetitions of r.*/
110 | object Loop {
111 | def apply(r: Term, minRepetitions: Term, maxRepetitions: Term): Term =
112 | FunctionApplication(
113 | QualifiedIdentifier(Identifier(SSymbol(RegexLoop))),
114 | Seq(r, minRepetitions, maxRepetitions)
115 | )
116 | def apply(r: Term, minRepetitions: Term): Term =
117 | FunctionApplication(
118 | QualifiedIdentifier(Identifier(SSymbol(RegexLoop))),
119 | Seq(r, minRepetitions)
120 | )
121 | def unapplySeq(term: Term): Option[Seq[Term]] = term match {
122 | case FunctionApplication(
123 | QualifiedIdentifier(
124 | Identifier(SSymbol(RegexRange), Seq()),
125 | None
126 | ), seqTerm) if seqTerm.length == 2 || seqTerm.length == 3 => Some(seqTerm)
127 | case _ => None
128 | }
129 | }
130 |
131 | /** Empty Regular Expression */
132 | object Empty extends Operation0 { override val name = RegexEmpty }
133 |
134 | /** All characters Regular Expression */
135 | object AllChar extends Operation0 { override val name = RegexAllChar }
136 | }
137 |
138 | /**
139 | Following functions are under the --strings-exp option. They are under active refinement. Once they are stable, we will move them to the default mode. Please let us know when you have some suggestions.
140 | */
141 | object Experimental {
142 | /** String Contain. Arguments (s,t) where s and t are string terms. It returns true if the string s contains the string t. This function determines whether the string t can be found within the string s, returning true or false as appropriate. */
143 | object Contains extends Operation2 { override val name = StringContains }
144 |
145 | /** String IndexOf. Arguments (s, t, i) where s is a string, t is a non-empty string and i is a non-negative integer. This function returns the position of the first occurrence of the specified value t in the string s after the index i. It returns -1 if the value to search for never occurs. */
146 | object IndexOf extends Operation3 { override val name = StringIndexOf }
147 |
148 | /** String Replacement. Arguments (s, t1, t2) where s, t1 and t2 are string terms, t1 is non-empty. This function searches the string s for the specified value t1, and returns a new string where the first occurrence of the specified value t1 is replaced by the string t2. */
149 | object Replace extends Operation3 { override val name = StringReplace }
150 |
151 | /** String PrefixOf. Arguments (s, t) where s and t are string terms. It returns true if the string s is a prefix of the string t. */
152 | object PrefixOf extends Operation2 { override val name = StringPrefixOf }
153 |
154 | /** String SuffixOf. Arguments (s, t) where s and t are string terms. It returns true if the string s is a suffix of the string t. */
155 | object SuffixOf extends Operation2 { override val name = StringSuffixOf }
156 |
157 | /** String To Integer Conversion. Argument s where s is a string term. It returns the corresponding natural number if s is valid; otherwise, it returns -1. */
158 | object StringToInt extends Operation1 { override val name = StringStringToInt }
159 |
160 | /** Integer To String Conversion. Argument s where i is an integer term. It returns the corresponding string if i is a natural number; otherwise, it returns an empty string. */
161 | object IntToString extends Operation1 { override val name = StringIntToString }
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/theories/package.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 |
3 | /** Provides constructors and extractors to build theory specific trees
4 | *
5 | * Theory trees are not concrete abstract syntax trees, but simply helpers
6 | * to properly construct the underlying low level {{smtlib.parser.Terms AST}}.
7 | *
8 | * This design choice is made to reflect how the SMT-LIB format is described,
9 | * and also seems to work well as most operations on trees only need to be
10 | * defined for the core ASTs. Many theories operations such as "+", "-", "div"
11 | * are really a special case of the general
12 | * {{smtlib.parser.Terms.FunctionApplication FunctionApplication}}.
13 | *
14 | * Each theory is defined in its own object named after the theory, e.g.
15 | * {theories.Ints}, which contains objects with `apply` and `unapply` (usually
16 | * factored out in some abstract {{theory.Operations}} traits) to build and
17 | * extract correct expressions in the theory.
18 | */
19 | package object theories {
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/trees/TermsOps.scala:
--------------------------------------------------------------------------------
1 | package smtlib.trees
2 |
3 | import Terms._
4 |
5 | object TermsOps {
6 |
7 | /* ========================
8 | Operations on Sort
9 | ========================
10 | */
11 |
12 | /** Applies a function to each sort in post-order
13 | *
14 | * The mapping is done starting from the leaf of the sort tree. For
15 | * each node, first apply recursively the postMap on the children
16 | * from left to right, then apply the function to the current sort
17 | * with the new children.
18 | *
19 | * @param f the function to apply. If it returns None then do not
20 | * update the corresponding node.
21 | * @param sort the sort to traverse
22 | * @return the new sort after applying the mapping
23 | */
24 | def postMap(f: (Sort) => Option[Sort])(sort: Sort): Sort = {
25 | val rec = postMap(f) _
26 | val Sort(id, subSorts) = sort
27 |
28 | val recSorts = subSorts.map(rec)
29 |
30 | val newSort = {
31 | if( recSorts.zip(subSorts).exists{ case (bef, aft) => bef ne aft } )
32 | Sort(id, recSorts)
33 | else
34 | sort
35 | }
36 |
37 | f(newSort).getOrElse(newSort)
38 | }
39 |
40 |
41 | /** Applies a function to each sort in pre-order
42 | *
43 | * The mapping is done starting from the root of the sort tree. For
44 | * each node, first apply the function to the current node, then
45 | * do it recursively on the children from left to right.
46 | *
47 | * @param f the function to apply. If it returns None then do not
48 | * update the corresponding node
49 | * @param sort the sort to traverse
50 | * @return the new sort after applying the mapping
51 | * @note this operation can diverge if f is not well formed
52 | */
53 | def preMap(f: (Sort) => Option[Sort])(sort: Sort): Sort = {
54 | val rec = preMap(f) _
55 | val newSort = f(sort).getOrElse(sort)
56 | val Sort(id, subSorts) = newSort
57 |
58 | val recSorts = subSorts.map(rec)
59 |
60 | if( recSorts.zip(subSorts).exists{ case (bef, aft) => bef ne aft } )
61 | Sort(id, recSorts)
62 | else
63 | newSort
64 | }
65 |
66 |
67 | def postTraversal(f: (Sort) => Unit)(sort: Sort): Unit = {
68 | val rec = postTraversal(f) _
69 | val Sort(_, subSorts) = sort
70 | subSorts.foreach(rec)
71 | f(sort)
72 | }
73 |
74 | def preTraversal(f: (Sort) => Unit)(sort: Sort): Unit = {
75 | val rec = preTraversal(f) _
76 | val Sort(_, subSorts) = sort
77 | f(sort)
78 | subSorts.foreach(rec)
79 | }
80 |
81 |
82 | def fold[T](f: (Sort, Seq[T]) => T)(sort: Sort): T = {
83 | val rec = fold(f) _
84 | val Sort(_, ss) = sort
85 | f(sort, ss.map(rec))
86 | }
87 |
88 |
89 | def exists(matcher: (Sort) => Boolean)(sort: Sort): Boolean =
90 | fold[Boolean]({ (s, subs) => matcher(s) || subs.contains(true) } )(sort)
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/src/main/scala/smtlib/trees/TreesOps.scala:
--------------------------------------------------------------------------------
1 | package smtlib.trees
2 |
3 |
4 | /** Generic and useful operations on entire trees
5 | *
6 | * This contains most traversal operations that can be
7 | * simply described as applying some function over the whole
8 | * tree. Mappings are more complex as they need to return
9 | * new trees, and would usually be defined as a full tree transformer
10 | * as it needs to return different type for each exact tree.
11 | */
12 | object TreesOps {
13 |
14 | def count(p: (Tree) => Boolean)(t: Tree): Int = {
15 | val folder = new TreeFolder {
16 | type R = Int
17 | override def combine(node: Tree, counts: Seq[Int]) =
18 | counts.sum + (if(p(node)) 1 else 0)
19 | }
20 | folder.fold(t)
21 | }
22 |
23 | def exists(p: (Tree) => Boolean)(t: Tree): Boolean = {
24 | val folder = new TreeFolder {
25 | type R = Boolean
26 | override def combine(node: Tree, cs: Seq[Boolean]) =
27 | cs.exists(b => b) || p(node)
28 | }
29 | folder.fold(t)
30 | }
31 |
32 | def forall(p: (Tree) => Boolean)(t: Tree): Boolean = {
33 | val folder = new TreeFolder {
34 | type R = Boolean
35 | override def combine(node: Tree, cs: Seq[Boolean]) =
36 | cs.forall(b => b) && p(node)
37 | }
38 | folder.fold(t)
39 | }
40 |
41 | def fold[T](f: (Tree, Seq[T]) => T)(t: Tree): T = {
42 | val folder = new TreeFolder {
43 | type R = T
44 | override def combine(node: Tree, cs: Seq[T]): T = f(node, cs)
45 | }
46 | folder.fold(t)
47 | }
48 |
49 |
50 | def foreach(f: (Tree) => Unit)(t: Tree): Unit = {
51 | val traverser = new TreeTraverser {
52 | override def combine(tree: Tree): Unit = f(tree)
53 | }
54 | traverser.traverse(t)
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/test/scala/smtlib/common/BinaryTests.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package common
3 |
4 | import org.scalatest.funsuite.AnyFunSuite
5 |
6 | class BinaryTests extends AnyFunSuite {
7 |
8 | test("toIntBits works with one bit") {
9 | assert(Binary(List(true)).toIntBits === 1)
10 | assert(Binary(List(false)).toIntBits === 0)
11 | }
12 |
13 | test("toIntBits works with a few bits") {
14 | assert(Binary(List(true, true)).toIntBits === 3)
15 | assert(Binary(List(true, false, true)).toIntBits === 5)
16 | }
17 |
18 | test("toIntBits correctly ignores leading zeros") {
19 | assert(Binary(List(false, true)).toIntBits === 1)
20 | assert(Binary(List(false, true, false, true)).toIntBits === 5)
21 | }
22 |
23 | test("toIntBits works with exactly 32 digits") {
24 | val allOnes: List[Boolean] = List[Boolean]().padTo(32, true)
25 | assert(Binary(allOnes).toIntBits === -1)
26 | }
27 |
28 | test("toIntBits ignores digits after 32") {
29 | val allOnes: List[Boolean] = List[Boolean]().padTo(32, true)
30 | assert(Binary(true :: allOnes).toIntBits === -1)
31 | assert(Binary(false :: allOnes).toIntBits === -1)
32 | assert(Binary(true :: false :: allOnes).toIntBits === -1)
33 | assert(Binary(false :: true :: allOnes).toIntBits === -1)
34 |
35 | val allZeros: List[Boolean] = List[Boolean]().padTo(32, false)
36 | assert(Binary(true :: allZeros).toIntBits === 0)
37 | assert(Binary(false :: allZeros).toIntBits === 0)
38 | assert(Binary(true :: false :: allZeros).toIntBits === 0)
39 | assert(Binary(false :: true :: allZeros).toIntBits === 0)
40 | }
41 |
42 | test("toLongBits works with one bit") {
43 | assert(Binary(List(true)).toLongBits === 1)
44 | assert(Binary(List(false)).toLongBits === 0)
45 | }
46 |
47 | test("toLongBits works with a few bits") {
48 | assert(Binary(List(true, true)).toLongBits === 3)
49 | assert(Binary(List(true, false, true)).toLongBits === 5)
50 | }
51 |
52 | test("toLongBits correctly ignores leading zeros") {
53 | assert(Binary(List(false, true)).toLongBits === 1)
54 | assert(Binary(List(false, true, false, true)).toLongBits === 5)
55 | }
56 |
57 | test("toInt works with one bit") {
58 | assert(Binary(List(true)).toInt === -1)
59 | assert(Binary(List(false)).toInt === 0)
60 | }
61 |
62 | test("toInt works with a few bits") {
63 | assert(Binary(List(true, true)).toInt === -1)
64 | assert(Binary(List(false, true, true)).toInt === 3)
65 | assert(Binary(List(false, true, false, true)).toInt === 5)
66 | assert(Binary(List(true, false, true)).toInt === -3)
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/src/test/scala/smtlib/common/HexadecimalTests.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package common
3 |
4 | import org.scalatest.funsuite.AnyFunSuite
5 |
6 | class HexadecimalTests extends AnyFunSuite {
7 |
8 | test("Build hexadecimal with one digit string") {
9 | val zero = Hexadecimal.fromString("0")
10 | assert(zero !== None)
11 | zero.foreach(zero => assert(zero.repr === "0"))
12 |
13 | val one = Hexadecimal.fromString("1")
14 | assert(one !== None)
15 | one.foreach(one => assert(one.repr === "1"))
16 |
17 | val ten = Hexadecimal.fromString("A")
18 | assert(ten !== None)
19 | ten.foreach(ten => assert(ten.repr === "A"))
20 | }
21 |
22 | test("Build hexadecimal with strings of multiple digits") {
23 | val hexa1 = Hexadecimal.fromString("12AB")
24 | assert(hexa1 !== None)
25 | hexa1.foreach(hexa1 => assert(hexa1.repr === "12AB"))
26 |
27 | val hexa2 = Hexadecimal.fromString("00F2")
28 | assert(hexa2 !== None)
29 | hexa2.foreach(hexa2 => assert(hexa2.repr === "00F2"))
30 | }
31 |
32 | test("Build hexadecimal with lower caps is represented as upper caps") {
33 | val hexa1 = Hexadecimal.fromString("a")
34 | assert(hexa1 !== None)
35 | hexa1.foreach(hexa1 => assert(hexa1.repr === "A"))
36 |
37 | val hexa2 = Hexadecimal.fromString("00fa")
38 | assert(hexa2 !== None)
39 | hexa2.foreach(hexa2 => assert(hexa2.repr === "00FA"))
40 | }
41 |
42 | test("Build hexadecimal from an invalid string returns None") {
43 | val hexa1 = Hexadecimal.fromString("g")
44 | assert(hexa1 === None)
45 |
46 | val hexa2 = Hexadecimal.fromString("0g")
47 | assert(hexa2 === None)
48 |
49 | val hexa3 = Hexadecimal.fromString("g001")
50 | assert(hexa3 === None)
51 | }
52 |
53 |
54 | test("toInt returns correct value for small positive numbers") {
55 | assert(Hexadecimal.fromString("0").get.toInt === 0)
56 | assert(Hexadecimal.fromString("1").get.toInt === 1)
57 | assert(Hexadecimal.fromString("a").get.toInt === 10)
58 | assert(Hexadecimal.fromString("f").get.toInt === 15)
59 | assert(Hexadecimal.fromString("10").get.toInt === 16)
60 | assert(Hexadecimal.fromString("1a").get.toInt === 26)
61 | assert(Hexadecimal.fromString("001a").get.toInt === 26)
62 | assert(Hexadecimal.fromString("3a").get.toInt === 58)
63 | }
64 |
65 | test("toInt returns correct value for negative numbers") {
66 | assert(Hexadecimal.fromString("FFFFFFFF").get.toInt === -1)
67 | assert(Hexadecimal.fromString("FFFFFFFE").get.toInt === -2)
68 | assert(Hexadecimal.fromString("80000000").get.toInt === -2147483648)
69 | }
70 |
71 | test("toInt ignores leading bits above 32") {
72 | assert(Hexadecimal.fromString("0000003a").get.toInt === 58)
73 | assert(Hexadecimal.fromString("000000003a").get.toInt === 58)
74 | assert(Hexadecimal.fromString("FF0000003a").get.toInt === 58)
75 | assert(Hexadecimal.fromString("FFFFFFFFFF").get.toInt === -1)
76 | assert(Hexadecimal.fromString("00FFFFFFFF").get.toInt === -1)
77 | }
78 |
79 | test("fromInt converts positive ints to hexadecimal") {
80 | assert(Hexadecimal.fromInt(0).repr === "00000000")
81 | assert(Hexadecimal.fromInt(1).repr === "00000001")
82 | assert(Hexadecimal.fromInt(15).repr === "0000000F")
83 | assert(Hexadecimal.fromInt(30).repr === "0000001E")
84 | assert(Hexadecimal.fromInt(2147483647).repr === "7FFFFFFF")
85 | }
86 |
87 | test("fromInt converts negative ints to hexadecimal") {
88 | assert(Hexadecimal.fromInt(-1).repr === "FFFFFFFF")
89 | assert(Hexadecimal.fromInt(-2).repr === "FFFFFFFE")
90 | assert(Hexadecimal.fromInt(-81).repr === "FFFFFFAF")
91 | assert(Hexadecimal.fromInt(-2147483648).repr === "80000000")
92 | }
93 |
94 | test("fromByte converts positive bytes to hexadecimal") {
95 | assert(Hexadecimal.fromByte(0).repr === "00")
96 | assert(Hexadecimal.fromByte(1).repr === "01")
97 | assert(Hexadecimal.fromByte(15).repr === "0F")
98 | assert(Hexadecimal.fromByte(30).repr === "1E")
99 | assert(Hexadecimal.fromByte(127).repr === "7F")
100 | }
101 |
102 | test("fromByte converts negative int to hexadecimal") {
103 | assert(Hexadecimal.fromByte(-1).repr === "FF")
104 | assert(Hexadecimal.fromByte(-2).repr === "FE")
105 | assert(Hexadecimal.fromByte(-81).repr === "AF")
106 | assert(Hexadecimal.fromByte(-128).repr === "80")
107 | }
108 |
109 | test("fromShort converts positive bytes to hexadecimal") {
110 | assert(Hexadecimal.fromShort(0).repr === "0000")
111 | assert(Hexadecimal.fromShort(1).repr === "0001")
112 | assert(Hexadecimal.fromShort(15).repr === "000F")
113 | assert(Hexadecimal.fromShort(30).repr === "001E")
114 | assert(Hexadecimal.fromShort(32767).repr === "7FFF")
115 | }
116 |
117 | test("fromShort converts negative int to hexadecimal") {
118 | assert(Hexadecimal.fromShort(-1).repr === "FFFF")
119 | assert(Hexadecimal.fromShort(-2).repr === "FFFE")
120 | assert(Hexadecimal.fromShort(-81).repr === "FFAF")
121 | assert(Hexadecimal.fromShort(-32768).repr === "8000")
122 | }
123 |
124 | test("fromBigInt converts positive ints to hexadecimal") {
125 | assert(Hexadecimal.fromBigInt(0, 1).repr === "0")
126 | assert(Hexadecimal.fromBigInt(1, 1).repr === "1")
127 | assert(Hexadecimal.fromBigInt(15,1).repr === "F")
128 | assert(Hexadecimal.fromBigInt(0, 2).repr === "00")
129 | assert(Hexadecimal.fromBigInt(1, 2).repr === "01")
130 | assert(Hexadecimal.fromBigInt(15,2).repr === "0F")
131 | assert(Hexadecimal.fromBigInt(30,2).repr === "1E")
132 | }
133 |
134 | test("fromBigInt ignores ints leading digits if not enough digits") {
135 | assert(Hexadecimal.fromBigInt(16, 1).repr === "0")
136 | assert(Hexadecimal.fromBigInt(17, 1).repr === "1")
137 | assert(Hexadecimal.fromBigInt(31, 1).repr === "F")
138 | }
139 |
140 | test("fromBigInt converts negative ints to hexadecimal") {
141 | assert(Hexadecimal.fromBigInt(-1, 1).repr === "F")
142 | assert(Hexadecimal.fromBigInt(-2, 1).repr === "E")
143 | assert(Hexadecimal.fromBigInt(-1, 2).repr === "FF")
144 | assert(Hexadecimal.fromBigInt(-2, 2).repr === "FE")
145 | assert(Hexadecimal.fromBigInt(-81,2).repr === "AF")
146 | assert(Hexadecimal.fromBigInt(-1, 4).repr === "FFFF")
147 |
148 | assert(Hexadecimal.fromBigInt(-128, 2).repr === "80")
149 | assert(Hexadecimal.fromBigInt(-128, 4).repr === "FF80")
150 | assert(Hexadecimal.fromBigInt(-127, 4).repr === "FF81")
151 | assert(Hexadecimal.fromBigInt(-129, 4).repr === "FF7F")
152 | }
153 |
154 | test("fromBigInt ignores leading '1's for negative ints") {
155 | assert(Hexadecimal.fromBigInt(-128, 1).repr === "0")
156 | assert(Hexadecimal.fromBigInt(-127, 1).repr === "1")
157 | assert(Hexadecimal.fromBigInt(-129, 1).repr === "F")
158 | assert(Hexadecimal.fromBigInt(-32768, 1).repr === "0")
159 |
160 | assert(Hexadecimal.fromBigInt(-16, 1).repr === "0")
161 | assert(Hexadecimal.fromBigInt(-81, 1).repr === "F")
162 | assert(Hexadecimal.fromBigInt(-18, 1).repr === "E")
163 | assert(Hexadecimal.fromBigInt(-19, 1).repr === "D")
164 | assert(Hexadecimal.fromBigInt(-28, 1).repr === "4")
165 | }
166 |
167 | }
168 |
--------------------------------------------------------------------------------
/src/test/scala/smtlib/common/LinkedListTests.scala:
--------------------------------------------------------------------------------
1 | package smtlib.common
2 |
3 | import org.scalatest.funsuite.AnyFunSuite
4 |
5 | class LinkedListTests extends AnyFunSuite {
6 |
7 |
8 | test("append one element on empty list pop the same element") {
9 | val l = new LinkedList[Int]
10 | l.append(3)
11 | assert(l.pop() === 3)
12 | }
13 |
14 | test("multiple appends pop in same order") {
15 | val l = new LinkedList[Int]
16 | l.append(2)
17 | l.append(3)
18 | l.append(1)
19 | assert(l.pop() === 2)
20 | assert(l.pop() === 3)
21 | assert(l.pop() === 1)
22 | }
23 |
24 | test("append with same element does duplicate the element") {
25 | val l = new LinkedList[Int]
26 | l.append(2)
27 | l.append(2)
28 | l.append(1)
29 | assert(l.pop() === 2)
30 | assert(l.pop() === 2)
31 | assert(l.pop() === 1)
32 | }
33 |
34 | test("mixing appends and pops work as expected") {
35 | val l = new LinkedList[Int]
36 | l.append(2)
37 | l.append(3)
38 | assert(l.pop() === 2)
39 | l.append(1)
40 | assert(l.pop() === 3)
41 | l.append(0)
42 | assert(l.pop() === 1)
43 | assert(l.pop() === 0)
44 | }
45 |
46 | test("prepend one element on empty list pop the same element") {
47 | val l = new LinkedList[Int]
48 | l.prepend(3)
49 | assert(l.pop() === 3)
50 | }
51 |
52 | test("multiple preprends pop in reverse order") {
53 | val l = new LinkedList[Int]
54 | l.prepend(2)
55 | l.prepend(3)
56 | l.prepend(1)
57 | assert(l.pop() === 1)
58 | assert(l.pop() === 3)
59 | assert(l.pop() === 2)
60 | }
61 |
62 | test("prepend with same element does duplicate the element") {
63 | val l = new LinkedList[Int]
64 | l.prepend(2)
65 | l.prepend(2)
66 | l.prepend(1)
67 | assert(l.pop() === 1)
68 | assert(l.pop() === 2)
69 | assert(l.pop() === 2)
70 | }
71 |
72 | test("mixing prepends and pops work as expected") {
73 | val l = new LinkedList[Int]
74 | l.prepend(2)
75 | l.prepend(3)
76 | assert(l.pop() === 3)
77 | l.prepend(1)
78 | assert(l.pop() === 1)
79 | l.prepend(0)
80 | assert(l.pop() === 0)
81 | assert(l.pop() === 2)
82 | }
83 |
84 | test("mixing prepends, appends and pops work as expected") {
85 | val l = new LinkedList[Int]
86 | l.append(42)
87 | l.append(22)
88 | l.prepend(2)
89 | l.prepend(3)
90 | l.append(12)
91 | assert(l.pop() === 3)
92 | l.prepend(10)
93 | l.append(17)
94 | assert(l.pop() === 10)
95 | assert(l.pop() === 2)
96 | assert(l.pop() === 42)
97 | assert(l.pop() === 22)
98 | l.append(7)
99 | assert(l.pop() === 12)
100 | assert(l.pop() === 17)
101 | assert(l.pop() === 7)
102 | }
103 |
104 | test("size of empty list is 0") {
105 | val l = new LinkedList[Int]
106 | assert(l.size === 0)
107 | }
108 |
109 | test("size of list of 1 element is 1") {
110 | val l = new LinkedList[Int]
111 | l.append(21)
112 | assert(l.size === 1)
113 | }
114 |
115 | test("size of list of 2 elements is 2") {
116 | val l = new LinkedList[Int]
117 | l.append(21)
118 | l.append(11)
119 | assert(l.size === 2)
120 | }
121 |
122 | test("size is consistent with appends and pops") {
123 | val l = new LinkedList[Int]
124 | assert(l.size === 0)
125 | l.append(21)
126 | assert(l.size === 1)
127 | l.pop()
128 | assert(l.size === 0)
129 | l.append(11)
130 | l.append(42)
131 | assert(l.size === 2)
132 | l.pop()
133 | assert(l.size === 1)
134 | }
135 |
136 | test("isEmpty returns true with newly created list") {
137 | val l = new LinkedList[Int]
138 | assert(l.isEmpty)
139 | }
140 | test("isEmpty returns false with one append") {
141 | val l = new LinkedList[Int]
142 | l.append(1)
143 | assert(!l.isEmpty)
144 | }
145 | test("isEmpty returns false with one prepend") {
146 | val l = new LinkedList[Int]
147 | l.prepend(1)
148 | assert(!l.isEmpty)
149 | }
150 | test("isEmpty returns true if enough pop make the list empty again") {
151 | val l = new LinkedList[Int]
152 | l.prepend(1)
153 | l.pop()
154 | assert(l.isEmpty)
155 | }
156 |
157 | test("isEmpty is not true after a single pop that does not make the list empty") {
158 | val l = new LinkedList[Int]
159 | l.append(2)
160 | l.prepend(3)
161 | assert(!l.isEmpty)
162 | l.pop()
163 | assert(!l.isEmpty)
164 | }
165 | test("isEmpty is eventually true after enough pops") {
166 | val l = new LinkedList[Int]
167 | l.append(2)
168 | l.prepend(3)
169 | l.append(4)
170 | assert(!l.isEmpty)
171 | l.pop()
172 | l.pop()
173 | l.pop()
174 | assert(l.isEmpty)
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/src/test/scala/smtlib/common/SynchronousPipedReader.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package common
3 |
4 | import java.io.Reader
5 | import scala.collection.mutable.ArrayBuffer
6 | import scala.collection.mutable.Queue
7 |
8 |
9 | /*
10 | * Implements Java Reader class and crash on any blocking call.
11 | * It is meant to be used to make sure the Lexer is not doing any
12 | * read call when not enough data is available.
13 | *
14 | * It provides method for directly writing to the pipe.
15 | */
16 | class SynchronousPipedReader extends Reader {
17 |
18 | private val buffy = new Queue[Int]()
19 |
20 | override def close(): Unit = {}
21 |
22 | override def read(chars: Array[Char], off: Int, len: Int): Int = {
23 | var i = 0
24 | while(i < len) {
25 | chars(i + off) = buffy.dequeue().toChar
26 | i += 1
27 | }
28 | len
29 | }
30 |
31 | override def ready(): Boolean = buffy.nonEmpty
32 |
33 | def write(i: Int): Unit = {
34 | buffy.enqueue(i)
35 | }
36 |
37 | def write(str: String): Unit = str.toCharArray.foreach(this.write(_))
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/test/scala/smtlib/parser/TermsOpsTests.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package trees
3 |
4 | import org.scalatest.funsuite.AnyFunSuite
5 |
6 | import Terms._
7 | import TermsOps._
8 |
9 | class TermsOpsTests extends AnyFunSuite {
10 |
11 | val s1 = Sort(Identifier(SSymbol("S1")))
12 | val s2 = Sort(Identifier(SSymbol("S2")))
13 | val s3 = Sort(Identifier(SSymbol("S3")), Seq(s1, s2))
14 |
15 | def sortId(s: Sort): Option[Sort] = Some(s)
16 |
17 | def s12s2(s: Sort): Option[Sort] = if(s == s1) Some(s2) else None
18 |
19 | test("postMap with empty function do not change simple sort") {
20 | assert(postMap((s: Sort) => None)(s1) === s1)
21 | assert(postMap((s: Sort) => None)(s2) === s2)
22 | }
23 |
24 | test("postMap with empty function do not change composed sort") {
25 | assert(postMap((s: Sort) => None)(s3) === s3)
26 | }
27 |
28 | test("postMap with id maps simple sorts to themselves") {
29 | assert(postMap(sortId)(s1) === s1)
30 | assert(postMap(sortId)(s2) === s2)
31 | }
32 |
33 | test("postMap with id maps composed sorts to themselves") {
34 | assert(postMap(sortId)(s3) === s3)
35 | }
36 |
37 | test("postMap with simple mapping works on simple term") {
38 | assert(postMap(s12s2)(s1) === s2)
39 | assert(postMap(s12s2)(s2) === s2)
40 | }
41 |
42 | test("postMap with simple mapping works on a leaf of a composed term") {
43 | assert(postMap(s12s2)(s3) === Sort(Identifier(SSymbol("S3")), Seq(s2, s2)))
44 | }
45 |
46 |
47 | test("preMap with empty function do not change simple sort") {
48 | assert(preMap((s: Sort) => None)(s1) === s1)
49 | assert(preMap((s: Sort) => None)(s2) === s2)
50 | }
51 |
52 | test("preMap with empty function do not change composed sort") {
53 | assert(preMap((s: Sort) => None)(s3) === s3)
54 | }
55 |
56 | test("preMap with id maps simple sorts to themselves") {
57 | assert(preMap(sortId)(s1) === s1)
58 | assert(preMap(sortId)(s2) === s2)
59 | }
60 |
61 | test("preMap with id maps composed sorts to themselves") {
62 | assert(preMap(sortId)(s3) === s3)
63 | }
64 |
65 | test("preMap with simple mapping works on simple term") {
66 | assert(preMap(s12s2)(s1) === s2)
67 | assert(preMap(s12s2)(s2) === s2)
68 | }
69 |
70 | test("preMap with simple mapping works on a leaf of a composed term") {
71 | assert(preMap(s12s2)(s3) === Sort(Identifier(SSymbol("S3")), Seq(s2, s2)))
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/test/scala/smtlib/parser/TreesOpsTests.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package trees
3 |
4 | import org.scalatest.funsuite.AnyFunSuite
5 |
6 | import Terms._
7 | import Commands._
8 | import TreesOps._
9 |
10 | class TreesOpsTests extends AnyFunSuite {
11 |
12 | val s1 = Sort(Identifier(SSymbol("S1")))
13 | val s2 = Sort(Identifier(SSymbol("S2")))
14 | val s3 = Sort(Identifier(SSymbol("S3")), Seq(s1, s2))
15 |
16 | val v1 = QualifiedIdentifier(Identifier(SSymbol("v1")))
17 | val v2 = QualifiedIdentifier(Identifier(SSymbol("v2")))
18 | val v3 = QualifiedIdentifier(Identifier(SSymbol("v3")))
19 |
20 | val f1 = QualifiedIdentifier(Identifier(SSymbol("f1")))
21 | val f2 = QualifiedIdentifier(Identifier(SSymbol("f2")))
22 | val f3 = QualifiedIdentifier(Identifier(SSymbol("f3")))
23 |
24 | test("count function is 1 if exactly one variable") {
25 | assert(count(t => t == v1)(v1) === 1)
26 | }
27 | test("count function is 0 if variable has different name") {
28 | assert(count(t => t == v2)(v1) === 0)
29 | }
30 | test("count function finds and count variable just once") {
31 | assert(count(t => t == v1)(FunctionApplication(f1, Seq(v1))) === 1)
32 | assert(count(t => t == v1)(FunctionApplication(f1, Seq(v1, v2))) === 1)
33 | assert(count(t => t == v2)(FunctionApplication(f1, Seq(v1, v2))) === 1)
34 | }
35 | test("count function finds and count variable several times") {
36 | assert(count(t => t == v1)(FunctionApplication(f1, Seq(v1))) === 1)
37 | assert(count(t => t == v1)(FunctionApplication(f1, Seq(v1, v1))) === 2)
38 | assert(count(t => t == v1)(FunctionApplication(f1, Seq(v1, v2, v1))) === 2)
39 | assert(count(t => t == v1)(FunctionApplication(f1, Seq(FunctionApplication(f2, Seq(v1, v2)), v1, v2, v1))) === 3)
40 | }
41 |
42 | test("count function finds and count variable in commands") {
43 | assert(count(t => t == v1)(Assert(FunctionApplication(f1, Seq(v1)))) === 1)
44 | assert(count(t => t == v1)(Assert(FunctionApplication(f1, Seq(FunctionApplication(f2, Seq(v1, v2)), v1, v2, v1)))) === 3)
45 | }
46 |
47 | test("count function finds and count literals just once") {
48 | assert(count(t => t == SNumeral(42))(FunctionApplication(f1, Seq(SNumeral(42)))) === 1)
49 | assert(count(t => t == SNumeral(42))(FunctionApplication(f1, Seq(SNumeral(42), SNumeral(17)))) === 1)
50 | assert(count(t => t == SNumeral(42))(FunctionApplication(f1, Seq(SNumeral(0), SNumeral(42)))) === 1)
51 | }
52 | test("count function finds and count literals several times") {
53 | assert(count(t => t == SNumeral(42))(FunctionApplication(f1, Seq(SNumeral(42)))) === 1)
54 | assert(count(t => t == SNumeral(42))(FunctionApplication(f1, Seq(SNumeral(42), SNumeral(42)))) === 2)
55 | assert(count(t => t == SNumeral(42))(FunctionApplication(f1, Seq(SNumeral(42), SNumeral(17), SNumeral(42)))) === 2)
56 | assert(count(t => t == SNumeral(42))(FunctionApplication(f1, Seq(FunctionApplication(f2, Seq(SNumeral(42), v2)), SNumeral(42), v2, SNumeral(42)))) === 3)
57 | }
58 |
59 | test("exists function finds a variable that appears once") {
60 | assert(exists(t => t == v1)(FunctionApplication(f1, Seq(v1))) === true)
61 | assert(exists(t => t == v1)(FunctionApplication(f1, Seq(v1, v2))) === true)
62 | assert(exists(t => t == v2)(FunctionApplication(f1, Seq(v1, v2))) === true)
63 | }
64 | test("exists function does not find a variable that does not appears once") {
65 | assert(exists(t => t == v2)(FunctionApplication(f1, Seq(v1))) === false)
66 | assert(exists(t => t == v3)(FunctionApplication(f1, Seq(v1, v2))) === false)
67 | assert(exists(t => t == v3)(FunctionApplication(f1, Seq(v1, v2))) === false)
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/src/test/scala/smtlib/theories/ArraysExTests.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package theories
3 |
4 | import trees.Terms._
5 | import ArraysEx._
6 | import Ints.{IntSort, NumeralLit}
7 |
8 | import org.scalatest.funsuite.AnyFunSuite
9 |
10 | class ArraysExTests extends AnyFunSuite {
11 |
12 | override def suiteName = "ArraysEx Theory test suite"
13 |
14 | test("Array sort is correctly constructed and extracted") {
15 | ArraySort(IntSort(), IntSort()) match {
16 | case ArraySort(IntSort(), IntSort()) => assert(true)
17 | case _ => assert(false)
18 | }
19 | }
20 |
21 | test("Select is correctly constructed and extracted") {
22 | val a = QualifiedIdentifier(SimpleIdentifier(SSymbol("a")))
23 | Select(a, NumeralLit(0)) match {
24 | case Select(x, NumeralLit(i)) =>
25 | assert(x === a)
26 | assert(i === 0)
27 | case _ => assert(false)
28 | }
29 | }
30 |
31 | test("Store is correctly constructed and extracted") {
32 | val a = QualifiedIdentifier(SimpleIdentifier(SSymbol("a")))
33 | Store(a, NumeralLit(0), NumeralLit(12)) match {
34 | case Store(x, NumeralLit(i), NumeralLit(v)) =>
35 | assert(x === a)
36 | assert(i === 0)
37 | assert(v === 12)
38 | case _ => assert(false)
39 | }
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/test/scala/smtlib/theories/CoreTests.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package theories
3 |
4 | import trees.Terms._
5 | import Core._
6 |
7 | import org.scalatest.funsuite.AnyFunSuite
8 |
9 | class CoreTests extends AnyFunSuite {
10 |
11 | override def suiteName = "Core Theory test suite"
12 |
13 | test("Bool sort") {
14 | val s = BoolSort()
15 |
16 | s match {
17 | case BoolSort() => assert(true)
18 | case _ => assert(false)
19 | }
20 | }
21 |
22 | test("literals") {
23 | val t = True()
24 | val f = False()
25 |
26 | t match {
27 | case False() => assert(false)
28 | case True() => assert(true)
29 | case _ => assert(false)
30 | }
31 |
32 | f match {
33 | case True() => assert(false)
34 | case False() => assert(true)
35 | case _ => assert(false)
36 | }
37 | }
38 |
39 | test("basic boolean op") {
40 | val t = True()
41 | val f = False()
42 |
43 | val not = Not(t)
44 | not match {
45 | case Not(x) =>
46 | assert(x == t)
47 | case _ => assert(false)
48 | }
49 |
50 | val ortf = Or(t, f)
51 | val ortt = Or(t, t)
52 | val orff = Or(f, f)
53 |
54 | ortf match {
55 | case And(x, y) => assert(false)
56 | case Or(x, y) =>
57 | assert(x == t)
58 | assert(y == f)
59 | case _ => assert(false)
60 | }
61 |
62 | val and = And(t, f)
63 | and match {
64 | case Or(x, y) => assert(false)
65 | case And(x, y) =>
66 | assert(x == t)
67 | assert(y == f)
68 | case _ => assert(false)
69 | }
70 |
71 | val xor = Xor(t, f)
72 | xor match {
73 | case Or(x, y) => assert(false)
74 | case And(x, y) => assert(false)
75 | case Xor(x, y) =>
76 | assert(x == t)
77 | assert(y == f)
78 | case _ => assert(false)
79 | }
80 |
81 | val implies = Implies(t, f)
82 | implies match {
83 | case Or(x, y) => assert(false)
84 | case And(x, y) => assert(false)
85 | case Implies(x, y) =>
86 | assert(x == t)
87 | assert(y == f)
88 | case _ => assert(false)
89 | }
90 |
91 | }
92 |
93 | //test("And varargs constructor properly builds formulas") {
94 | // val f1 = QualifiedIdentifier(SimpleIdentifier(SSymbol("f1")))
95 | // val f2 = QualifiedIdentifier(SimpleIdentifier(SSymbol("f2")))
96 | // val f3 = QualifiedIdentifier(SimpleIdentifier(SSymbol("f3")))
97 |
98 | // val a0 = And()
99 | // assert(a0 === True())
100 |
101 | // val a1 = And(f1)
102 | // assert(a1 === f1)
103 |
104 | // val a2 = And(f1, f2, f3)
105 | // assert(a2 === And(f1, And(f2, f3)) || a2 === And(And(f1, f2), f3))
106 | //}
107 |
108 | //test("Or varargs constructor properly builds formulas") {
109 | // val f1 = QualifiedIdentifier(SimpleIdentifier(SSymbol("f1")))
110 | // val f2 = QualifiedIdentifier(SimpleIdentifier(SSymbol("f2")))
111 | // val f3 = QualifiedIdentifier(SimpleIdentifier(SSymbol("f3")))
112 |
113 | // val o0 = Or()
114 | // assert(o0 === False())
115 |
116 | // val o1 = Or(f1)
117 | // assert(o1 === f1)
118 |
119 | // val o2 = Or(f1, f2, f3)
120 | // assert(o2 === Or(f1, Or(f2, f3)) || o2 === Or(Or(f1, f2), f3))
121 | //}
122 |
123 | test("smtlib format") {
124 | import parser.Parser
125 |
126 | Parser.fromString("true").parseTerm match {
127 | case True() => assert(true)
128 | case _ => assert(false)
129 | }
130 |
131 | Parser.fromString("false").parseTerm match {
132 | case False() => assert(true)
133 | case _ => assert(false)
134 | }
135 |
136 | Parser.fromString("(not true)").parseTerm match {
137 | case False() => assert(false)
138 | case True() => assert(false)
139 | case Not(True()) => assert(true)
140 | case _ => assert(false)
141 | }
142 |
143 | Parser.fromString("(or true false)").parseTerm match {
144 | case False() => assert(false)
145 | case True() => assert(false)
146 | case Not(True()) => assert(false)
147 | case And(True(), False()) => assert(false)
148 | case Or(True(), True()) => assert(false)
149 | case Or(True(), False()) => assert(true)
150 | case _ => assert(false)
151 | }
152 |
153 | Parser.fromString("(and true false)").parseTerm match {
154 | case False() => assert(false)
155 | case True() => assert(false)
156 | case Not(True()) => assert(false)
157 | case Or(True(), False()) => assert(false)
158 | case And(True(), True()) => assert(false)
159 | case And(True(), False()) => assert(true)
160 | case _ => assert(false)
161 | }
162 |
163 | Parser.fromString("(=> true false)").parseTerm match {
164 | case False() => assert(false)
165 | case True() => assert(false)
166 | case Not(True()) => assert(false)
167 | case Or(True(), False()) => assert(false)
168 | case Implies(True(), True()) => assert(false)
169 | case Implies(True(), False()) => assert(true)
170 | case _ => assert(false)
171 | }
172 |
173 | Parser.fromString("(xor true false)").parseTerm match {
174 | case False() => assert(false)
175 | case True() => assert(false)
176 | case Not(True()) => assert(false)
177 | case Or(True(), False()) => assert(false)
178 | case Xor(True(), True()) => assert(false)
179 | case Xor(True(), False()) => assert(true)
180 | case _ => assert(false)
181 | }
182 | }
183 |
184 | }
185 |
--------------------------------------------------------------------------------
/src/test/scala/smtlib/theories/IntsTests.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package theories
3 |
4 | import Ints._
5 |
6 | import org.scalatest.funsuite.AnyFunSuite
7 |
8 | class IntsTests extends AnyFunSuite {
9 |
10 | override def suiteName = "Ints theory test suite"
11 |
12 | test("IntSort is correctly constructed and extracted") {
13 | IntSort() match {
14 | case IntSort() => assert(true)
15 | case _ => assert(false)
16 | }
17 |
18 | IntSort() match {
19 | case FixedSizeBitVectors.BitVectorSort(_) => assert(false)
20 | case IntSort() => assert(true)
21 | case _ => assert(false)
22 | }
23 | }
24 |
25 | test("NumeralLit is correctly constructed and extracted") {
26 | val l1 = NumeralLit(42)
27 |
28 | l1 match {
29 | case NumeralLit(n) => assert(n === 42)
30 | case _ => assert(false)
31 | }
32 |
33 | }
34 |
35 | test("Divisible is correctly constructed and extracted") {
36 | Divisible(BigInt(3), NumeralLit(9)) match {
37 | case Divisible(d, NumeralLit(n)) =>
38 | assert(n === 9)
39 | assert(d === 3)
40 | case _ => assert(false)
41 | }
42 | }
43 |
44 | test("Neg is correctly constructed and extracted") {
45 | Neg(NumeralLit(23)) match {
46 | case Neg(NumeralLit(n)) => assert(n === 23)
47 | case _ => assert(false)
48 | }
49 | }
50 |
51 | test("Add is correctly constructed and extracted") {
52 | Add(NumeralLit(23), NumeralLit(112)) match {
53 | case Add(NumeralLit(n1), NumeralLit(n2)) =>
54 | assert(n1 === 23)
55 | assert(n2 === 112)
56 | case _ => assert(false)
57 | }
58 | }
59 |
60 | test("Sub is correctly constructed and extracted") {
61 | Sub(NumeralLit(23), NumeralLit(112)) match {
62 | case Sub(NumeralLit(n1), NumeralLit(n2)) =>
63 | assert(n1 === 23)
64 | assert(n2 === 112)
65 | case _ => assert(false)
66 | }
67 | }
68 |
69 | test("Mul is correctly constructed and extracted") {
70 | Mul(NumeralLit(23), NumeralLit(112)) match {
71 | case Mul(NumeralLit(n1), NumeralLit(n2)) =>
72 | assert(n1 === 23)
73 | assert(n2 === 112)
74 | case _ => assert(false)
75 | }
76 | }
77 |
78 | test("Div is correctly constructed and extracted") {
79 | Div(NumeralLit(10), NumeralLit(2)) match {
80 | case Div(NumeralLit(n1), NumeralLit(n2)) =>
81 | assert(n1 === 10)
82 | assert(n2 === 2)
83 | case _ => assert(false)
84 | }
85 | }
86 |
87 | test("Mod is correctly constructed and extracted") {
88 | Mod(NumeralLit(10), NumeralLit(2)) match {
89 | case Mod(NumeralLit(n1), NumeralLit(n2)) =>
90 | assert(n1 === 10)
91 | assert(n2 === 2)
92 | case _ => assert(false)
93 | }
94 | }
95 | test("Abs is correctly constructed and extracted") {
96 | Abs(NumeralLit(23)) match {
97 | case Abs(NumeralLit(n)) => assert(n === 23)
98 | case _ => assert(false)
99 | }
100 | }
101 |
102 |
103 | test("LessThan is correctly constructed and extracted") {
104 | LessThan(NumeralLit(10), NumeralLit(2)) match {
105 | case LessThan(NumeralLit(n1), NumeralLit(n2)) =>
106 | assert(n1 === 10)
107 | assert(n2 === 2)
108 | case _ => assert(false)
109 | }
110 | }
111 |
112 | test("LessEquals is correctly constructed and extracted") {
113 | LessEquals(NumeralLit(10), NumeralLit(2)) match {
114 | case LessEquals(NumeralLit(n1), NumeralLit(n2)) =>
115 | assert(n1 === 10)
116 | assert(n2 === 2)
117 | case _ => assert(false)
118 | }
119 | }
120 |
121 | test("GreaterThan is correctly constructed and extracted") {
122 | GreaterThan(NumeralLit(10), NumeralLit(2)) match {
123 | case GreaterThan(NumeralLit(n1), NumeralLit(n2)) =>
124 | assert(n1 === 10)
125 | assert(n2 === 2)
126 | case _ => assert(false)
127 | }
128 | }
129 |
130 | test("GreaterEquals is correctly constructed and extracted") {
131 | GreaterEquals(NumeralLit(10), NumeralLit(2)) match {
132 | case GreaterEquals(NumeralLit(n1), NumeralLit(n2)) =>
133 | assert(n1 === 10)
134 | assert(n2 === 2)
135 | case _ => assert(false)
136 | }
137 | }
138 |
139 | test("Extractors correctly extract parsed strings") {
140 | import parser.Parser
141 |
142 | Parser.fromString("12").parseTerm match {
143 | case NumeralLit(n) => assert(n == 12)
144 | case _ => assert(false)
145 | }
146 |
147 |
148 | Parser.fromString("(- 13)").parseTerm match {
149 | case Neg(NumeralLit(n)) => assert(n == 13)
150 | case _ => assert(false)
151 | }
152 | Parser.fromString("(- 13 17)").parseTerm match {
153 | case Sub(
154 | NumeralLit(n1),
155 | NumeralLit(n2)
156 | ) => assert(n1 == 13 && n2 == 17)
157 | case _ => assert(false)
158 | }
159 | Parser.fromString("(+ 13 17)").parseTerm match {
160 | case Add(
161 | NumeralLit(n1),
162 | NumeralLit(n2)
163 | ) => assert(n1 == 13 && n2 == 17)
164 | case _ => assert(false)
165 | }
166 | Parser.fromString("(* 13 17)").parseTerm match {
167 | case Mul(
168 | NumeralLit(n1),
169 | NumeralLit(n2)
170 | ) => assert(n1 == 13 && n2 == 17)
171 | case _ => assert(false)
172 | }
173 |
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/src/test/scala/smtlib/theories/RealsTests.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package theories
3 |
4 | import Reals._
5 |
6 | import org.scalatest.funsuite.AnyFunSuite
7 |
8 | class RealsTests extends AnyFunSuite {
9 |
10 | override def suiteName = "Reals theory test suite"
11 |
12 | test("Real sort") {
13 | RealSort() match {
14 | case RealSort() => assert(true)
15 | case _ => assert(false)
16 | }
17 |
18 | RealSort() match {
19 | case FixedSizeBitVectors.BitVectorSort(n) if n == 14 => assert(false)
20 | case FixedSizeBitVectors.BitVectorSort(n) if n == 32 => assert(false)
21 | case Ints.IntSort() => assert(false)
22 | case RealSort() => assert(true)
23 | case _ => assert(false)
24 | }
25 | }
26 |
27 | test("literals") {
28 | val l1 = NumeralLit(42)
29 |
30 | l1 match {
31 | case NumeralLit(n) => assert(n == 42)
32 | case _ => assert(false)
33 | }
34 |
35 | val l2 = DecimalLit(BigDecimal("13.41"))
36 |
37 | l2 match {
38 | case NumeralLit(n) => assert(false)
39 | case DecimalLit(d) => assert(d == BigDecimal("13.41"))
40 | case _ => assert(false)
41 | }
42 | }
43 |
44 |
45 | test("smtlib format") {
46 | import parser.Parser
47 |
48 | Parser.fromString("12").parseTerm match {
49 | case NumeralLit(n) => assert(n == 12)
50 | case _ => assert(false)
51 | }
52 |
53 |
54 | Parser.fromString("(- 13)").parseTerm match {
55 | case Neg(NumeralLit(n)) => assert(n == 13)
56 | case _ => assert(false)
57 | }
58 | Parser.fromString("(- 13 17)").parseTerm match {
59 | case Sub(
60 | NumeralLit(n1),
61 | NumeralLit(n2)
62 | ) => assert(n1 == 13 && n2 == 17)
63 | case _ => assert(false)
64 | }
65 | Parser.fromString("(+ 13 17)").parseTerm match {
66 | case Add(
67 | NumeralLit(n1),
68 | NumeralLit(n2)
69 | ) => assert(n1 == 13 && n2 == 17)
70 | case _ => assert(false)
71 | }
72 | Parser.fromString("(* 13 17)").parseTerm match {
73 | case Mul(
74 | NumeralLit(n1),
75 | NumeralLit(n2)
76 | ) => assert(n1 == 13 && n2 == 17)
77 | case _ => assert(false)
78 | }
79 |
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/test/scala/smtlib/theories/experimental/SetsTests.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package theories
3 | package experimental
4 |
5 | import trees.Terms._
6 |
7 | import Sets._
8 | import Ints.{IntSort, NumeralLit}
9 |
10 | import org.scalatest.funsuite.AnyFunSuite
11 | import org.scalatest.matchers.should.Matchers
12 |
13 | class SetsTests extends AnyFunSuite with Matchers {
14 |
15 | override def suiteName = "Set theory test suite"
16 |
17 | test("String sort correctly constructed and extracted") {
18 | SetSort(IntSort()) match {
19 | case SetSort(IntSort()) => assert(true)
20 | case _ => assert(false)
21 | }
22 |
23 | SetSort(IntSort()) match {
24 | case FixedSizeBitVectors.BitVectorSort(n) if n == 14 => assert(false)
25 | case FixedSizeBitVectors.BitVectorSort(n) if n == 32 => assert(false)
26 | case Ints.IntSort() => assert(false)
27 | case Reals.RealSort() => assert(false)
28 | case SetSort(IntSort()) => assert(true)
29 | case _ => assert(false)
30 | }
31 | }
32 |
33 | test("EmptySet is correctly constructed and extracted") {
34 | EmptySet(IntSort()) match {
35 | case EmptySet(IntSort()) => assert(true)
36 | case _ => assert(false)
37 | }
38 |
39 | EmptySet(IntSort()) match {
40 | case EmptySet(Reals.RealSort()) => assert(false)
41 | case NumeralLit(_) => assert(false)
42 | case EmptySet(IntSort()) => assert(true)
43 | case _ => ???
44 | }
45 | }
46 |
47 | test("Singleton is correctly constructed and extracted") {
48 | Singleton(NumeralLit(42)) match {
49 | case Singleton(NumeralLit(n)) => assert(n === 42)
50 | case _ => assert(false)
51 | }
52 |
53 | Singleton(EmptySet(IntSort())) match {
54 | case EmptySet(IntSort()) => assert(false)
55 | case Singleton(NumeralLit(_)) => assert(false)
56 | case Singleton(EmptySet(IntSort())) => assert(true)
57 | case _ => assert(false)
58 | }
59 | }
60 |
61 | test("Union is correctly constructed and extracted") {
62 | Union(EmptySet(IntSort()), Singleton(NumeralLit(42))) match {
63 | case Union(EmptySet(IntSort()), Singleton(NumeralLit(n))) => assert(n === 42)
64 | case _ => assert(false)
65 | }
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/src/test/scala/smtlib/theories/experimental/StringsTests.scala:
--------------------------------------------------------------------------------
1 | package smtlib
2 | package theories
3 | package experimental
4 |
5 | import trees.Terms._
6 |
7 | import Strings._
8 | import Ints.NumeralLit
9 |
10 | import org.scalatest.funsuite.AnyFunSuite
11 | import org.scalatest.matchers.should.Matchers
12 |
13 | class StringsTests extends AnyFunSuite with Matchers {
14 |
15 | override def suiteName = "Strings theory test suite"
16 |
17 | test("String sort correctly constructed and extracted") {
18 | StringSort() match {
19 | case StringSort() => assert(true)
20 | case _ => assert(false)
21 | }
22 |
23 | StringSort() match {
24 | case FixedSizeBitVectors.BitVectorSort(n) if n == 14 => assert(false)
25 | case FixedSizeBitVectors.BitVectorSort(n) if n == 32 => assert(false)
26 | case Ints.IntSort() => assert(false)
27 | case Reals.RealSort() => assert(false)
28 | case StringSort() => assert(true)
29 | case _ => assert(false)
30 | }
31 | }
32 |
33 | test("literals are correctly constructed and extracted") {
34 | val l1 = StringLit("abc")
35 |
36 | l1 match {
37 | case StringLit(n) => assert(n === "abc")
38 | case _ => assert(false)
39 | }
40 |
41 | val l2 = StringLit("")
42 |
43 | l2 match {
44 | case StringLit(n) => assert(n === "")
45 | case _ => assert(false)
46 | }
47 |
48 | val l3 = StringLit("with space")
49 |
50 | l3 match {
51 | case StringLit(n) => assert(n === "with space")
52 | case _ => assert(false)
53 | }
54 | }
55 |
56 | test("Length is correctly constructed and extracted") {
57 | val l1 = Length(StringLit("abcd"))
58 | l1 match {
59 | case Length(StringLit("abcd")) => assert(true)
60 | case _ => assert(false)
61 | }
62 |
63 |
64 | val l2 = Length(StringLit("aaaa"))
65 | l2 match {
66 | case Length(StringLit("aaaa")) => assert(true)
67 | case _ => assert(false)
68 | }
69 | }
70 |
71 | test("Concat is correctly constructed and extracted") {
72 | val c1 = Concat(StringLit("ab"), StringLit("cd"))
73 | c1 match {
74 | case Concat(StringLit("ab"), StringLit("cd")) => assert(true)
75 | case _ => assert(false)
76 | }
77 |
78 | val c2 = Concat(StringLit("ab"), StringLit("cd"), StringLit("ef"))
79 | c2 match {
80 | case Concat(StringLit("ab"), StringLit("cd"), StringLit("ef")) => assert(true)
81 | case _ => assert(false)
82 | }
83 |
84 | val c3 = Concat(StringLit("ab"), StringLit("cd"), StringLit("ef"))
85 | c3 match {
86 | case Concat(StringLit("ab")) => assert(false)
87 | case Concat(StringLit("ab"), StringLit("cd")) => assert(false)
88 | case Concat(StringLit("ab"), StringLit("cd"), StringLit("ef")) => assert(true)
89 | case _ => assert(false)
90 | }
91 |
92 | val c4 = Concat(StringLit("ab"), StringLit("cd"), StringLit("ef"))
93 | c4 match {
94 | case Concat(ts@_*) => {
95 | assert(ts(0) === StringLit("ab"))
96 | assert(ts(1) === StringLit("cd"))
97 | assert(ts(2) === StringLit("ef"))
98 | }
99 | case _ => assert(false)
100 | }
101 |
102 | }
103 |
104 | test("At is correctly constructed and extracted") {
105 | val a = At(StringLit("xxx"), NumeralLit(2))
106 | a match {
107 | case At(StringLit("xxx"), NumeralLit(two)) => assert(two === 2)
108 | case _ => assert(false)
109 | }
110 | }
111 |
112 | test("Substring is correctly constructed and extracted") {
113 | val s = Substring(StringLit("abcdef"), NumeralLit(2), NumeralLit(5))
114 | s match {
115 | case Substring(StringLit("abcdef"), NumeralLit(two), NumeralLit(five)) => {
116 | assert(two === 2)
117 | assert(five === 5)
118 | }
119 | case _ => assert(false)
120 | }
121 | }
122 |
123 |
124 | test("smtlib string format") {
125 | import parser.Parser
126 |
127 | implicit class TestParse(s: String) {
128 | def shouldParse(f: PartialFunction[Term, Any]) = {
129 | val term = Parser.fromString(s).parseTerm
130 | if(f.isDefinedAt(term)) f(term) else {
131 | sys.error("Term " + s + " wrongly parsed as " + term)
132 | }
133 | }
134 | def shouldParseTo(p: Term) = {
135 | Parser.fromString(s).parseTerm should equal(p)
136 | }
137 | }
138 |
139 |
140 | "\"abc\"" shouldParseTo
141 | StringLit("abc")
142 |
143 | "(str.++ \"a\" \"bc\" )" shouldParseTo
144 | Concat(StringLit("a"), StringLit("bc"))
145 |
146 | "(str.++ \"a\" \"bc\" \"def\" )" shouldParseTo
147 | Concat(StringLit("a"), StringLit("bc"), StringLit("def"))
148 |
149 | "(str.len \"abcd\")" shouldParseTo
150 | Length(StringLit("abcd"))
151 |
152 | "(str.at \"abcd\" 1)" shouldParseTo
153 | At(StringLit("abcd"), NumeralLit(1))
154 |
155 | "(str.substr \"abcdef\" 2 5)" shouldParseTo
156 | Substring(StringLit("abcdef"), NumeralLit(2), NumeralLit(5))
157 | }
158 | }
159 |
--------------------------------------------------------------------------------