├── lib ├── lazyz3 │ ├── version.rb │ ├── evaluator.rb │ └── extensions.rb └── lazyz3.rb ├── .gitignore ├── Gemfile ├── bin ├── setup └── console ├── test ├── test_helper.rb └── lazyz3 │ └── lazyz3_test.rb ├── Rakefile ├── Gemfile.lock ├── README.md └── z3rb-lazy.gemspec /lib/lazyz3/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module LazyZ3 4 | VERSION = "0.1.0" 5 | end 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /_yardoc/ 4 | /coverage/ 5 | /doc/ 6 | /pkg/ 7 | /spec/reports/ 8 | /tmp/ 9 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | # Specify your gem's dependencies in z3rb-lazy.gemspec 6 | gemspec 7 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | $LOAD_PATH.unshift File.expand_path("../lib", __dir__) 4 | require "lazyz3" 5 | 6 | require "minitest/autorun" 7 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "bundler/gem_tasks" 4 | require "rake/testtask" 5 | 6 | Rake::TestTask.new(:test) do |t| 7 | t.libs << "test" 8 | t.libs << "lib" 9 | t.test_files = FileList["test/**/*_test.rb"] 10 | end 11 | 12 | task default: :test 13 | -------------------------------------------------------------------------------- /lib/lazyz3.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "ast" 4 | 5 | module LazyZ3 6 | class Error < StandardError; end 7 | end 8 | 9 | def ss(kind, *children) 10 | LazyZ3::Z3Node.new(kind, children) 11 | end 12 | 13 | require_relative "lazyz3/version" 14 | require_relative "lazyz3/extensions" 15 | require_relative "lazyz3/evaluator" 16 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require "bundler/setup" 5 | require "lazyz3" 6 | 7 | # You can add fixtures and/or initialization code here to make experimenting 8 | # with your gem easier. You can also use a different console, if you like. 9 | 10 | # (If you use this, don't forget to add pry to your Gemfile!) 11 | # require "pry" 12 | # Pry.start 13 | 14 | require "irb" 15 | IRB.start(__FILE__) 16 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | lazyz3 (0.1.0) 5 | ast (~> 2.4) 6 | minitest (~> 5.0) 7 | rake (~> 13.0) 8 | z3 (~> 0.0.20220320) 9 | 10 | GEM 11 | remote: https://rubygems.org/ 12 | specs: 13 | ast (2.4.2) 14 | ffi (1.15.5) 15 | minitest (5.15.0) 16 | rake (13.0.6) 17 | z3 (0.0.20220320) 18 | ffi (~> 1.9) 19 | 20 | PLATFORMS 21 | x86_64-darwin-19 22 | 23 | DEPENDENCIES 24 | lazyz3! 25 | 26 | BUNDLED WITH 27 | 2.2.28 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Z3rb::Lazy 2 | 3 | Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/z3rb/lazy`. To experiment with that code, run `bin/console` for an interactive prompt. 4 | 5 | TODO: Delete this and the text above, and describe your gem 6 | 7 | ## Installation 8 | 9 | Add this line to your application's Gemfile: 10 | 11 | ```ruby 12 | gem 'z3rb-lazy' 13 | ``` 14 | 15 | And then execute: 16 | 17 | $ bundle install 18 | 19 | Or install it yourself as: 20 | 21 | $ gem install z3rb-lazy 22 | 23 | ## Usage 24 | 25 | TODO: Write usage instructions here 26 | 27 | ## Development 28 | 29 | After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. 30 | 31 | To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org). 32 | 33 | ## Contributing 34 | 35 | Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/z3rb-lazy. 36 | -------------------------------------------------------------------------------- /z3rb-lazy.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "lib/lazyz3/version" 4 | 5 | Gem::Specification.new do |spec| 6 | spec.name = "lazyz3" 7 | spec.version = LazyZ3::VERSION 8 | spec.authors = ["Sankha Narayan Guria"] 9 | spec.email = ["sankha93@gmail.com"] 10 | 11 | spec.summary = "Manipulate Z3 ASTs lazily" 12 | spec.homepage = "https://github.com/ngsankha/z3rb-lazy" 13 | spec.required_ruby_version = ">= 2.4.0" 14 | 15 | spec.metadata["homepage_uri"] = spec.homepage 16 | spec.metadata["source_code_uri"] = "https://github.com/ngsankha/z3rb-lazy" 17 | 18 | # Specify which files should be added to the gem when it is released. 19 | # The `git ls-files -z` loads the files in the RubyGem that have been added into git. 20 | spec.files = Dir.chdir(File.expand_path(__dir__)) do 21 | `git ls-files -z`.split("\x0").reject do |f| 22 | (f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)}) 23 | end 24 | end 25 | spec.bindir = "exe" 26 | spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } 27 | spec.require_paths = ["lib"] 28 | 29 | spec.add_dependency "rake", "~> 13.0" 30 | spec.add_dependency "minitest", "~> 5.0" 31 | spec.add_dependency "z3", "~> 0.0.20220320" 32 | spec.add_dependency "ast", "~> 2.4" 33 | 34 | # For more information and examples about making a new gem, checkout our 35 | # guide at: https://bundler.io/guides/creating_gem.html 36 | end 37 | -------------------------------------------------------------------------------- /lib/lazyz3/evaluator.rb: -------------------------------------------------------------------------------- 1 | require 'z3' 2 | 3 | module LazyZ3 4 | class Evaluator 5 | attr_reader :model 6 | 7 | def solve(expr) 8 | solver = Z3::Solver.new 9 | z3_expr = eval(expr, {}) 10 | solver.assert(z3_expr) 11 | result = solver.satisfiable? 12 | if result 13 | @model = {} 14 | solver.model.map { |k, _| 15 | @model[k.to_s] = solver.model.model_eval(k) 16 | } 17 | end 18 | result 19 | end 20 | 21 | private 22 | def eval(expr, env) 23 | if expr.is_a?(Integer) || expr.bool? 24 | expr 25 | elsif expr.is_a? Z3Node 26 | case expr.type 27 | when :const 28 | expr.children[0] 29 | when :var_int 30 | var_name = expr.children[0].to_s 31 | if env.key? var_name 32 | env[var_name] 33 | else 34 | var = Z3.Int(var_name) 35 | env[var_name] = var 36 | var 37 | end 38 | when :var_bool 39 | var_name = expr.children[0].to_s 40 | if env.key? var_name 41 | env[var_name] 42 | else 43 | var = Z3.Bool(var_name) 44 | env[var_name] = var 45 | var 46 | end 47 | when :send 48 | case expr.children[0] 49 | when :+ 50 | eval(expr.children[1], env) + eval(expr.children[2], env) 51 | when :- 52 | eval(expr.children[1], env) - eval(expr.children[2], env) 53 | when :* 54 | eval(expr.children[1], env) * eval(expr.children[2], env) 55 | when :/ 56 | eval(expr.children[1], env) / eval(expr.children[2], env) 57 | when :== 58 | eval(expr.children[1], env) == eval(expr.children[2], env) 59 | when :!= 60 | eval(expr.children[1], env) != eval(expr.children[2], env) 61 | when :< 62 | eval(expr.children[1], env) < eval(expr.children[2], env) 63 | when :> 64 | eval(expr.children[1], env) > eval(expr.children[2], env) 65 | when :<= 66 | eval(expr.children[1], env) <= eval(expr.children[2], env) 67 | when :>= 68 | eval(expr.children[1], env) >= eval(expr.children[2], env) 69 | when :& 70 | eval(expr.children[1], env) & eval(expr.children[2], env) 71 | when :| 72 | eval(expr.children[1], env) | eval(expr.children[2], env) 73 | when :! 74 | !eval(expr.children[1], env) 75 | else 76 | raise LazyZ3::Error, "no known mapping to Z3 for #{expr.children[1]}" 77 | end 78 | else 79 | raise LazyZ3::Error, "unexpected node type" 80 | end 81 | else 82 | raise LazyZ3::Error, "unexpected type" 83 | end 84 | end 85 | end 86 | 87 | def self.solve(expr) 88 | e = Evaluator.new 89 | e.solve(expr) 90 | end 91 | end 92 | 93 | -------------------------------------------------------------------------------- /test/lazyz3/lazyz3_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "test_helper" 4 | 5 | # module Z3IntegerRefinement 6 | # refine Integer do 7 | # prepend LazyZ3::Int 8 | # end 9 | # end 10 | 11 | # using Z3IntegerRefinement 12 | 13 | Integer.prepend LazyZ3::Int 14 | TrueClass.prepend LazyZ3::Bool 15 | FalseClass.prepend LazyZ3::Bool 16 | 17 | class LazyZ3::LazyZ3Test < Minitest::Test 18 | def test_that_it_has_a_version_number 19 | refute_nil ::LazyZ3::VERSION 20 | end 21 | 22 | def test_integers_behave_correctly 23 | assert_equal 5 + 3, 8 24 | assert_equal 5 - 3, 2 25 | assert_equal 5 * 3, 15 26 | assert_equal 5 / 3, 1 27 | assert 5 == 5 28 | assert 7 != 6 29 | assert 4 < 7 30 | assert 6 > 2 31 | assert 5 <= 5 32 | assert 3 <= 5 33 | assert 5 >= 5 34 | assert 5 >= 3 35 | end 36 | 37 | def test_booleans_behave_correctly 38 | assert true == true 39 | assert false == false 40 | assert true != false 41 | assert false != true 42 | end 43 | 44 | def test_bool_var 45 | assert_equal LazyZ3::var_bool(:x), ss(:var_bool, :x) 46 | end 47 | 48 | def test_int_var 49 | assert_equal LazyZ3::var_int(:x), ss(:var_int, :x) 50 | end 51 | 52 | def test_symbolic_int_add 53 | x = LazyZ3::var_int(:x) 54 | assert_equal (5 + x).to_s, ss(:send, :+, ss(:const, 5), x).to_s 55 | assert_equal (x + 5).to_s, ss(:send, :+, x, ss(:const, 5)).to_s 56 | assert_equal (x + x).to_s, ss(:send, :+, x, x).to_s 57 | end 58 | 59 | def test_symbolic_int_sub 60 | x = LazyZ3::var_int(:x) 61 | assert_equal (5 - x).to_s, ss(:send, :-, ss(:const, 5), x).to_s 62 | assert_equal (x - 5).to_s, ss(:send, :-, x, ss(:const, 5)).to_s 63 | assert_equal (x - x).to_s, ss(:send, :-, x, x).to_s 64 | end 65 | 66 | def test_symbolic_int_mul 67 | x = LazyZ3::var_int(:x) 68 | assert_equal (5 * x).to_s, ss(:send, :*, ss(:const, 5), x).to_s 69 | assert_equal (x * 5).to_s, ss(:send, :*, x, ss(:const, 5)).to_s 70 | assert_equal (x * x).to_s, ss(:send, :*, x, x).to_s 71 | end 72 | 73 | def test_symbolic_int_div 74 | x = LazyZ3::var_int(:x) 75 | assert_equal (5 / x).to_s, ss(:send, :"/", ss(:const, 5), x).to_s 76 | assert_equal (x / 5).to_s, ss(:send, :"/", x, ss(:const, 5)).to_s 77 | assert_equal (x / x).to_s, ss(:send, :"/", x, x).to_s 78 | end 79 | 80 | def test_symbolic_int_eql 81 | x = LazyZ3::var_int(:x) 82 | assert_equal (5 == x).to_s, ss(:send, :"==", ss(:const, 5), x).to_s 83 | assert_equal (x == 5).to_s, ss(:send, :"==", x, ss(:const, 5)).to_s 84 | assert_equal (x == x).to_s, ss(:send, :"==", x, x).to_s 85 | end 86 | 87 | def test_symbolic_int_neq 88 | x = LazyZ3::var_int(:x) 89 | assert_equal (5 != x).to_s, ss(:send, :"!=", ss(:const, 5), x).to_s 90 | assert_equal (x != 5).to_s, ss(:send, :"!=", x, ss(:const, 5)).to_s 91 | assert_equal (x != x).to_s, ss(:send, :"!=", x, x).to_s 92 | end 93 | 94 | def test_symbolic_int_lt 95 | x = LazyZ3::var_int(:x) 96 | assert_equal (5 < x).to_s, ss(:send, :"<", ss(:const, 5), x).to_s 97 | assert_equal (x < 5).to_s, ss(:send, :"<", x, ss(:const, 5)).to_s 98 | assert_equal (x < x).to_s, ss(:send, :"<", x, x).to_s 99 | end 100 | 101 | def test_symbolic_int_gt 102 | x = LazyZ3::var_int(:x) 103 | assert_equal (5 > x).to_s, ss(:send, :">", ss(:const, 5), x).to_s 104 | assert_equal (x > 5).to_s, ss(:send, :">", x, ss(:const, 5)).to_s 105 | assert_equal (x > x).to_s, ss(:send, :">", x, x).to_s 106 | end 107 | 108 | def test_symbolic_int_leq 109 | x = LazyZ3::var_int(:x) 110 | assert_equal (5 <= x).to_s, ss(:send, :"<=", ss(:const, 5), x).to_s 111 | assert_equal (x <= 5).to_s, ss(:send, :"<=", x, ss(:const, 5)).to_s 112 | assert_equal (x <= x).to_s, ss(:send, :"<=", x, x).to_s 113 | end 114 | 115 | def test_symbolic_int_geq 116 | x = LazyZ3::var_int(:x) 117 | assert_equal (5 >= x).to_s, ss(:send, :">=", ss(:const, 5), x).to_s 118 | assert_equal (x >= 5).to_s, ss(:send, :">=", x, ss(:const, 5)).to_s 119 | assert_equal (x >= x).to_s, ss(:send, :">=", x, x).to_s 120 | end 121 | 122 | def test_symbolic_bool_and 123 | x = LazyZ3::var_int(:x) 124 | assert_equal (true & x).to_s, ss(:send, :"&", ss(:const, true), x).to_s 125 | assert_equal (x & false).to_s, ss(:send, :"&", x, ss(:const, false)).to_s 126 | assert_equal (x & x).to_s, ss(:send, :"&", x, x).to_s 127 | end 128 | 129 | def test_symbolic_bool_or 130 | x = LazyZ3::var_int(:x) 131 | assert_equal (true | x).to_s, ss(:send, :"|", ss(:const, true), x).to_s 132 | assert_equal (x | false).to_s, ss(:send, :"|", x, ss(:const, false)).to_s 133 | assert_equal (x | x).to_s, ss(:send, :"|", x, x).to_s 134 | end 135 | 136 | def test_symbolic_bool_not 137 | x = LazyZ3::var_int(:x) 138 | assert_equal (!x).to_s, ss(:send, :!, x).to_s 139 | end 140 | 141 | def test_unsat 142 | x = LazyZ3::var_bool(:x) 143 | expr = x & (!x) 144 | refute LazyZ3::solve(expr) 145 | end 146 | 147 | def test_valid 148 | x = LazyZ3::var_int(:x) 149 | expr = ((x - 5) == 0) 150 | e = LazyZ3::Evaluator.new 151 | assert e.solve(expr) 152 | assert_equal e.model["x"], 5 153 | end 154 | 155 | def test_valid_bool 156 | x = LazyZ3::var_bool(:x) 157 | expr = (!x) 158 | e = LazyZ3::Evaluator.new 159 | assert e.solve(expr) 160 | assert_equal e.model["x"], false 161 | end 162 | end 163 | -------------------------------------------------------------------------------- /lib/lazyz3/extensions.rb: -------------------------------------------------------------------------------- 1 | module LazyZ3 2 | module Int 3 | def +(rhs) 4 | if rhs.is_a?(Z3Node) 5 | ss(:send, :+, ss(:const, self), rhs) 6 | else 7 | super(rhs) 8 | end 9 | end 10 | 11 | def -(rhs) 12 | if rhs.is_a?(Z3Node) 13 | ss(:send, :-, ss(:const, self), rhs) 14 | else 15 | super(rhs) 16 | end 17 | end 18 | 19 | def *(rhs) 20 | if rhs.is_a?(Z3Node) 21 | ss(:send, :*, ss(:const, self), rhs) 22 | else 23 | super(rhs) 24 | end 25 | end 26 | 27 | def /(rhs) 28 | if rhs.is_a?(Z3Node) 29 | ss(:send, :/, ss(:const, self), rhs) 30 | else 31 | super(rhs) 32 | end 33 | end 34 | 35 | def ==(rhs) 36 | if rhs.is_a?(Z3Node) 37 | ss(:send, :==, ss(:const, self), rhs) 38 | else 39 | super(rhs) 40 | end 41 | end 42 | 43 | def !=(rhs) 44 | if rhs.is_a?(Z3Node) 45 | ss(:send, :!=, ss(:const, self), rhs) 46 | else 47 | super(rhs) 48 | end 49 | end 50 | 51 | def <(rhs) 52 | if rhs.is_a?(Z3Node) 53 | ss(:send, :<, ss(:const, self), rhs) 54 | else 55 | super(rhs) 56 | end 57 | end 58 | 59 | def >(rhs) 60 | if rhs.is_a?(Z3Node) 61 | ss(:send, :>, ss(:const, self), rhs) 62 | else 63 | super(rhs) 64 | end 65 | end 66 | 67 | def <=(rhs) 68 | if rhs.is_a?(Z3Node) 69 | ss(:send, :<=, ss(:const, self), rhs) 70 | else 71 | super(rhs) 72 | end 73 | end 74 | 75 | def >=(rhs) 76 | if rhs.is_a?(Z3Node) 77 | ss(:send, :>=, ss(:const, self), rhs) 78 | else 79 | super(rhs) 80 | end 81 | end 82 | end 83 | 84 | module Bool 85 | def ==(rhs) 86 | if rhs.is_a?(Z3Node) 87 | ss(:send, :==, ss(:const, self), rhs) 88 | else 89 | super(rhs) 90 | end 91 | end 92 | 93 | def !=(rhs) 94 | if rhs.is_a?(Z3Node) 95 | ss(:send, :!=, ss(:const, self), rhs) 96 | else 97 | super(rhs) 98 | end 99 | end 100 | 101 | def &(rhs) 102 | if rhs.is_a?(Z3Node) 103 | ss(:send, :&, ss(:const, self), rhs) 104 | else 105 | super(rhs) 106 | end 107 | end 108 | 109 | def |(rhs) 110 | if rhs.is_a?(Z3Node) 111 | ss(:send, :|, ss(:const, self), rhs) 112 | else 113 | super(rhs) 114 | end 115 | end 116 | end 117 | 118 | def self.var_int(name) 119 | ss(:var_int, name) 120 | end 121 | 122 | def self.var_bool(name) 123 | ss(:var_bool, name) 124 | end 125 | 126 | class Z3Node < ::AST::Node 127 | def +(rhs) 128 | if rhs.is_a?(Z3Node) 129 | ss(:send, :+, self, rhs) 130 | elsif rhs.is_a?(Integer) || rhs.bool? 131 | ss(:send, :+, self, ss(:const, rhs)) 132 | else 133 | raise LazyZ3::Error, "unhandled type" 134 | end 135 | end 136 | 137 | def -(rhs) 138 | if rhs.is_a?(Z3Node) 139 | ss(:send, :-, self, rhs) 140 | elsif rhs.is_a?(Integer) || rhs.bool? 141 | ss(:send, :-, self, ss(:const, rhs)) 142 | else 143 | raise LazyZ3::Error, "unhandled type" 144 | end 145 | end 146 | 147 | def *(rhs) 148 | if rhs.is_a?(Z3Node) 149 | ss(:send, :*, self, rhs) 150 | elsif rhs.is_a?(Integer) || rhs.bool? 151 | ss(:send, :*, self, ss(:const, rhs)) 152 | else 153 | raise LazyZ3::Error, "unhandled type" 154 | end 155 | end 156 | 157 | def /(rhs) 158 | if rhs.is_a?(Z3Node) 159 | ss(:send, :/, self, rhs) 160 | elsif rhs.is_a?(Integer) || rhs.bool? 161 | ss(:send, :/, self, ss(:const, rhs)) 162 | else 163 | raise LazyZ3::Error, "unhandled type" 164 | end 165 | end 166 | 167 | def ==(rhs) 168 | if rhs.is_a?(Z3Node) 169 | ss(:send, :==, self, rhs) 170 | elsif rhs.is_a?(Integer) || rhs.bool? 171 | ss(:send, :==, self, ss(:const, rhs)) 172 | else 173 | raise LazyZ3::Error, "unhandled type" 174 | end 175 | end 176 | 177 | def !=(rhs) 178 | if rhs.is_a?(Z3Node) 179 | ss(:send, :!=, self, rhs) 180 | elsif rhs.is_a?(Integer) || rhs.bool? 181 | ss(:send, :!=, self, ss(:const, rhs)) 182 | else 183 | raise LazyZ3::Error, "unhandled type" 184 | end 185 | end 186 | 187 | def <(rhs) 188 | if rhs.is_a?(Z3Node) 189 | ss(:send, :<, self, rhs) 190 | elsif rhs.is_a?(Integer) || rhs.bool? 191 | ss(:send, :<, self, ss(:const, rhs)) 192 | else 193 | raise LazyZ3::Error, "unhandled type" 194 | end 195 | end 196 | 197 | def >(rhs) 198 | if rhs.is_a?(Z3Node) 199 | ss(:send, :>, self, rhs) 200 | elsif rhs.is_a?(Integer) || rhs.bool? 201 | ss(:send, :>, self, ss(:const, rhs)) 202 | else 203 | raise LazyZ3::Error, "unhandled type" 204 | end 205 | end 206 | 207 | def <=(rhs) 208 | if rhs.is_a?(Z3Node) 209 | ss(:send, :<=, self, rhs) 210 | elsif rhs.is_a?(Integer) || rhs.bool? 211 | ss(:send, :<=, self, ss(:const, rhs)) 212 | else 213 | raise LazyZ3::Error, "unhandled type" 214 | end 215 | end 216 | 217 | def >=(rhs) 218 | if rhs.is_a?(Z3Node) 219 | ss(:send, :>=, self, rhs) 220 | elsif rhs.is_a?(Integer) || rhs.bool? 221 | ss(:send, :>=, self, ss(:const, rhs)) 222 | else 223 | raise LazyZ3::Error, "unhandled type" 224 | end 225 | end 226 | 227 | def &(rhs) 228 | if rhs.is_a?(Z3Node) 229 | ss(:send, :&, self, rhs) 230 | elsif rhs.is_a?(Integer) || rhs.bool? 231 | ss(:send, :&, self, ss(:const, rhs)) 232 | else 233 | raise LazyZ3::Error, "unhandled type" 234 | end 235 | end 236 | 237 | def |(rhs) 238 | if rhs.is_a?(Z3Node) 239 | ss(:send, :|, self, rhs) 240 | elsif rhs.is_a?(Integer) || rhs.bool? 241 | ss(:send, :|, self, ss(:const, rhs)) 242 | else 243 | raise LazyZ3::Error, "unhandled type" 244 | end 245 | end 246 | 247 | def ! 248 | ss(:send, :!, self) 249 | end 250 | end 251 | end 252 | 253 | class BasicObject 254 | def bool? 255 | self.is_a?(::FalseClass) || self.is_a?(::TrueClass) 256 | end 257 | end 258 | --------------------------------------------------------------------------------