├── .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 | --------------------------------------------------------------------------------